I have the following class:
public class ListDemo<T> : IList<T>
{
private List<T> list = new List<T>(); // Internal list
public void Add(T item)
{
// Do your pre-add logic here
list.Add(item); // add to the internal list
// Do your post-add logic here
}
// Implement all IList<T> methods, just passing through to list, such as:
}
Then in my code I have:
AuditList<Entities.SetupCenterCode> _centerCodes = new AuditList<Entities.SetupCenterCode>();
using (Logistics.Data.ConfigurationWCF svc = new Data.ConfigurationWCF())
{
_centerCodes = svc.GetCenterCodes(_entity);
foreach (var item in _centerCodes)
{
item.StartTracking();
}
}
But I get an error here with the conversion because svc.GetCenterCodes(_entity); returns a traditional List<>
How can I solve this, is strange because my custom ListDemo class is for built for generic list.
Any clue?
You can have a private constructor that takes a list and then use the implicit operator to cast directly from list:
public class MyList<T>
{
private List<T> myList;
private MyList(List<T> myList)
{
this.myList = myList;
}
public static implicit operator MyList<T>(List<T> list)
{
return new MyList<T>(list);
}
}
Then, Your rest of the code will work without a change:
List<SomeObject> list = new List<SomeObject>();
MyList<SomeObject> myList = list;
Related
My question is in the title.
How can I add items to my generic, custom list without using the .Add() method ?
public class MyArray<T>
{
public List<T> _myArray;
public MyArray()
{
_myArray = new List<T>();
}
public void Add(T obj)
{
//I wanna add item without using the .Add() method.
}
}
Well, you can create an index variable internally:
class MyArray<T>
{
public List<T> _myArray;
private int index = 0;
public MyArray()
{
_myArray = new List<T>();
}
public void Add(T obj)
{
_myArray[index++] = obj;
}
}
Note, that if/when you add a Remove method, you'll need to make sure the index value is modified to accommodate the change etc.
public class ItemStore {
private Dictionary<Type, List<object>> _items = new Dictionary<Type, List<object>>();
public void AddItem(object item) {
var type = item.GetType();
if (!_items.ContainsKey(type)) {
_items[type] = new List<object>();
}
_items[type].Add(item);
}
public IEnumerable<T> GetItems<T>() {
if(!_items.ContainsKey(typeof(T))) {
return new List<T>();
}
return _items[typeof(T)].Cast<T>();
}
}
(The real scenario is more complex, and it is a library used in multiple Projects knowing nothing about the concrete types.... )
The Cast<T>() in GetItems() is consuming quite some time. So I would prefere to avoid it. Is there any way to avoid it in C# - because actually the list already contains the correct types?
You need to modify the internal structure of this class a bit to not use generics in the items lookup because we need to underlying type of the stored list to be the correct type. This requires a little reflection when creating the list. We can also make AddItem and GetItems a little more efficient by avoiding extra lookups:
public class ItemStore {
private Dictionary<Type, IList> _items = new Dictionary<Type, IList>();
public void AddItem(object item) {
var type = item.GetType();
IList list;
if (!_items.TryGetValue(type, out list)) {
var listType = typeof(List<>).MakeGenericType(type);
list = (IList)Activator.CreateInstance(listType);
_items[type] = list;
}
list.Add(item);
}
public IEnumerable<T> GetItems<T>() {
IList list;
if(!_items.TryGetValue(typeof(T), out list)) {
return Enumerable.Empty<T>();
} else {
return (IEnumerable<T>)list;
}
}
}
If you can modify the signature of AddItem this could be even simpler (no reflection), but given you've said this is an over simplification, I will leave the public API unchanged.
Use IList instead of List(T)
Make AddItem() method generic
public class ItemStore
{
private Dictionary<Type, IList> _items = new Dictionary<Type, IList>();
public void AddItem<T>(T item)
{
var type = typeof(T);
if (!_items.ContainsKey(type))
{
_items[type] = new List<T>();
}
_items[type].Add(item);
}
public IEnumerable<T> GetItems<T>()
{
if (!_items.ContainsKey(typeof(T)))
{
return new List<T>();
}
return (List<T>)_items[typeof(T)];
}
}
You could make your method AddItem generic, which would allow you to store List<T> instances in your dictionary (whose generic TValue parameter should be IList in this case).
public class ItemStore
{
private Dictionary<Type, IList> _items = new Dictionary<Type, IList>();
public void AddItem<T>(T item)
{
IList objList;
if (!_items.TryGetValue(typeof(T), out objList))
{
objList = new List<T>();
_items[typeof(T)] = objList;
}
objList.Add(item);
}
public IEnumerable<T> GetItems<T>()
{
IList objList;
return
(_items.TryGetValue(typeof(T), out objList)) ? (List<T>)objList
: new List<T>();
}
}
I have a following field declared in my class -
private Dictionary<T, List<IEventProcessor<T>>> _subscribers = new Dictionary<T, List<IEventProcessor<T>>> ();
I also have the following method:
public GenEvent<T> GetEvent ()
one of the methods of this class needs to lookup an event processor from the _subscribers dictionary. How do I declare the type of local variable list?
public void Process()
{
var ev = GetEvent();
TYPE list;
if (_subscribers.TryGetValue(ev.EType, out list) ){
foreach (var sub in list) {
// do something
}
}
List<IEventProcessor<T>> list;
It should look like this:
public class MyClass<T>
{
private Dictionary<T, List<IEventProcessor<T>>> _subscribers = new Dictionary<T, List<IEventProcessor<T>>> ();
public GenEvent<T> GetEvent() {}
public void Process()
{
GenEvent<T> ev = GetEvent();
List<IEventProcessor<T>> list;
if (_subscribers.TryGetValue(ev.EType, out list) )
{
foreach (IEventProcessor<T> sub in list)
{
// do something
}
}
}
}
I'm trying to create the extension method AddRange for HashSet so I can do something like this:
var list = new List<Item>{ new Item(), new Item(), new Item() };
var hashset = new HashSet<Item>();
hashset.AddRange(list);
This is what I have so far:
public static void AddRange<T>(this ICollection<T> collection, List<T> list)
{
foreach (var item in list)
{
collection.Add(item);
}
}
Problem is, when I try to use AddRange, I'm getting this compiler error:
The type arguments for method 'AddRange<T>(System.Collections.Generic.ICollection<T>, System.Collections.Generic.List<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
In other words, I have to end up using this instead:
hashset.AddRange<Item>(list);
What am I doing wrong here?
Use
hashSet.UnionWith<Item>(list);
Your code works fine for me:
using System.Collections.Generic;
static class Extensions
{
public static void AddRange<T>(this ICollection<T> collection, List<T> list)
{
foreach (var item in list)
{
collection.Add(item);
}
}
}
class Item {}
class Test
{
static void Main()
{
var list = new List<Item>{ new Item(), new Item(), new Item() };
var hashset = new HashSet<Item>();
hashset.AddRange(list);
}
}
Could you give a similar short but complete program which fails to compile?
I have a class that contains a collection. I want to provided a method or property that returns the contents of the collection. It's ok if calling classes can modify the individual objects but I do not want them adding or removing object from the actual collection. I have been copying all the objects to a new list, but now I'm thinking that I could just return the list as IEnumerable<>.
In the simplified example below is GetListC the best way to return a read only version of a collection?
public class MyClass
{
private List<string> mylist;
public MyClass()
{
mylist = new List<string>();
}
public void Add(string toAdd)
{
mylist.Add(toAdd);
}
//Returns the list directly
public List<String> GetListA
{
get
{
return mylist;
}
}
//returns a copy of the list
public List<String> GetListB
{
get
{
List<string> returnList = new List<string>();
foreach (string st in this.mylist)
{
returnList.Add(st);
}
return returnList;
}
}
//Returns the list as IEnumerable
public IEnumerable<string> GetListC
{
get
{
return this.mylist.AsEnumerable<String>();
}
}
}
You can use List(T).AsReadOnly():
return this.mylist.AsReadOnly()
which will return a ReadOnlyCollection.
Just use ReadOnlyCollection class, it is supported since .NET 2.0
Use the generic ReadOnlyCollection class (Collection.AsReadOnly()). It doesn't copy any objects which may have some strange results when the underlying collection is changed.
var foo = new List<int> { 3, 1, 2 };
var bar = foo.AsReadOnly();
foreach (var x in bar) Console.WriteLine(x);
foo.Sort();
foreach (var x in bar) Console.WriteLine(x);
But if you don't want a copy, that's the best solution.
I prefer returning IEnumerable, but you don't need to cast. Just do
public IEnumerable<string> StringList { get { return myList; }
List<string> is an IEnumerable<string>