I try to give my generic interface a base.
Declaration:
public interface IMyInterface
{
ObservableCollection<object> Items {get;}
}
public interface IMyInterface<TValue>
{
new ObservableCollection<TValue> Items {get;} //Try to override base Items
}
Implementation
public abstract class MyBase<T> : IMyInterface<T>
{
private ObservableCollection<T> = _Items;
public ObservableCollection<T> Items
{
get
{
return _Items;
}
}
public ObservableCollection<T> IMyInterface.Items
{
get
{
return _Items as ObservableCollection<T>; //Reason?
}
}
Usage:
void foo(object sender, NotifyCollectionChangedEventArgs e)
{
foreach(IMyInterface obj in e.NewItems) // e.NewItems are derived from MyBase
{
var item = obj.Items; // Problem: item = null
//Do something
}
}
But if i try to use it in that way, i got null.
What is my mistake? Exists any other, better ways?
Your implementation is the problem here. The cast will result in null. You can only use covariant interfaces, so the first Items should be an IEnumerable<object>:
public interface IMyInterface
{
IEnumerable<object> Items { get; }
}
public interface IMyInterface<TValue> : IMyInterface
{
new ObservableCollection<TValue> Items { get; } //Try to override base Items
}
public abstract class MyBase<T> : IMyInterface<T> where T : class
{
private ObservableCollection<T> _Items;
public ObservableCollection<T> Items
{
get
{
return _Items;
}
}
IEnumerable<object> IMyInterface.Items
{
get
{
return _Items;
}
}
}
Related
Say that I have a series of classes:
abstract class MyClass { }
class MyFirstClass : MyClass { }
class MySecondClass : MyClass { }
class MyThirdClass : MyClass { }
I want to do something based on a configurable list of these derived class types, so I want to store the chosen class's Types in a list. I know I could create a List<Type>, but I could theoretically add any class to that list. On the other hand, a List<MyClass> would be a list of instances of these classes, rather than a list of the types themselves. I could also create an enum with one value that corresponds to each derived type, and have a factory method to create the correct one as needed, but that's at least two more places I'd have to update when I added MyFourthClass.
Is there a way to do something like new List<typeof(MyClass)>() = new[] { typeof(MyFirstClass), typeof(MyThirdClass)}? Does the very fact I'm asking this question imply a problem with my design?
What you want is a generic list of types (List<Type>) but like you said, you can insert any type there. The solution I can give you is to implement your own List of types from MyClass, for instance:
class TypeMyClassList : IList<Type>
{
private readonly List<Type> _list = new List<Type>();
private bool CheckType(Type type)
{
return type.IsSubclassOf(typeof (MyClass)) || typeof (MyClass) == type;
}
public IEnumerator<Type> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(Type item)
{
if (CheckType(item))
_list.Add(item);
else
throw new InvalidOperationException("You can't add other types than derived from A");
}
public void Clear()
{
_list.Clear();
}
public bool Contains(Type item)
{
return _list.Contains(item);
}
public void CopyTo(Type[] array, int arrayIndex)
{
_list.CopyTo(array, arrayIndex);
}
public bool Remove(Type item)
{
return _list.Remove(item);
}
public int Count
{
get { return _list.Count; }
}
public bool IsReadOnly { get { return false; } }
public int IndexOf(Type item)
{
return _list.IndexOf(item);
}
public void Insert(int index, Type item)
{
if (!CheckType(item))
throw new InvalidOperationException("You can't insert other types than derived from A");
_list.Add(item);
}
public void RemoveAt(int index)
{
_list.RemoveAt(index);
}
public Type this[int index]
{
get
{
return _list[index];
}
set
{
Insert(index, value);
}
}
}
Then you could do thinks like this that you want:
var typeMyClassList = new TypeMyClassList
{
typeof(MyClass),
typeof(MyClassA),
typeof(MyClassB)
};
The bad thing is that it will allows to do this in compilance time (the error will be raised on runtime):
var typeMyClassList = new TypeMyClassList
{
typeof(MyClass),
typeof(MyClassA),
typeof(MyClassB),
typeof(string)
};
There's no way to do this with static, compile-time type checking. Your best bet is to go with a solution like Raul OtaƱo's in which you do your checks at runtime.
Why can't you do this? The reason is that C# lacks static metaclass types. A metaclass is the class of a class. In other words, the instances of a metaclass are themselves classes. If C# had metaclasses, you could say something like IList<MyClassMeta> (or perhaps the syntax would be IList<meta MyClass> and the compiler would only allow you to pass MyClass (or its subclasses) as "instances", e.g.,
IList<meta MyClass> list;
list.Add(MyClass);
I've been wanting this functionality for a long time, but I don't expect it any time soon.
I've created a class which derives from IEnumerable<T>. T is a OQTemplate, and this one implements IXmlSerializable correctly. But I don't know how to implement the following class.
public class OQTemplateCollection : IEnumerable<OQTemplate>, IEnumerable
{
private readonly List<OQTemplate> entries;
public OQTemplateCollection()
{
this.entries = new List<OQTemplate>();
}
public OQTemplateCollection(IEnumerable<OQTemplate> source)
{
this.entries = new List<OQTemplate>(source);
}
public void Add(OQTemplate qt)
{
entries.Add(qt);
}
public IEnumerator<OQTemplate> GetEnumerator()
{
return entries.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public OQTemplate this[int index]
{
get { return entries[index]; }
}
}
I'd like just to have a XML like this:
<OQTemplateCollection>
<OQTemplate ... />
<OQTemplate ... />
</OQTemplateCollection>
I have something link this:
public abstract class Wrapper<T, TWrapped>: where TWrapped : Wrapper<T, TWrapped>
{
protected T baseObject;
protected ICollection<T> baseList;
protected ICollection<TWrapped> wrappedList;
public Wrapper (T base, ICollection<T> baseList, ICollection<TWrapped> wrappedList) { }
}
Then when I derive from it I need to to something like:
public class Base { }
public class Sample: Wrapper<Base, Sample> { }
Is there a way to remove the TWrapped and create a reference to the derived type? I tried using ICollection<Wrapped<T>> but then I remember that there is no covariance in ICollection.
EDIT: Clarifications, what I want with this wrapper is provide removal funcionality (and some other things) within the object (I can't change the base object so I need a wrapper to give this funcionality and manipulate it). This abstract class will have methods like this:
void Remove()
{
while(this.baseList.Remove(baseObject));
this.baseList = null;
while(this.wrappedList.Remove((TWrapped)this));
this.wrappedList = null;
}
I end up changing the logic of how I'm going to make the lists sync and allow Items to remove themselves. I created a new class to hold a collection of the wrapped items:
public interface IWrapper<TModel>
{
TModel Model { get; }
}
public class WrapperCollection<TWrapper, TModel> : ObservableCollection<TWrapper> where TWrapper : IWrapper<TModel>
{
protected IList<TModel> modelList;
public ReadOnlyObservableCollection<TWrapper> AsReadOnly { get; private set; }
protected WrapperCollection(IList<TModel> modelList)
{
this.modelList = modelList;
AsReadOnly = new ReadOnlyObservableCollection<TWrapper>(this);
}
public WrapperCollection(IList<TModel> modelList, Func<TModel, TWrapper> newWrapper)
:this(modelList)
{
foreach (TModel model in modelList)
this.Items.Add(newWrapper(model));
}
public WrapperCollection(IList<TModel> modelList, Func<TModel, WrapperCollection<TWrapper, TModel>, TWrapper> newWrapper)
: this(modelList)
{
foreach (TModel model in modelList)
this.Items.Add(newWrapper(model, this));
}
protected override void ClearItems()
{
modelList.Clear();
base.ClearItems();
}
protected override void InsertItem(int index, TWrapper item)
{
modelList.Insert(index, item.Model);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
modelList.RemoveAt(index);
base.RemoveItem(index);
}
protected override void SetItem(int index, TWrapper item)
{
modelList[index] = item.Model;
base.SetItem(index, item);
}
}
Using the sample class:
public class wrappedInt: IWrapper<int>
{
private WrapperCollection<wrappedInt, int> list;
public Model { get; private set; }
public wrappedInt(int source, WrapperCollection<wrappedInt, int> list)
{
this.Model = source;
this.list = list;
}
public void RemoveMe()
{
if (list != null)
{
list.Remove(this);
list = null;
}
}
}
Then I can instantiate a collection with new WrapperCollection<wrappedInt, int>(listOfInts, (model, parent) => new wrappedInt(model, parent));.
Why can I not cast a List<ObjBase> as List<Obj>? Why does the following not work:
internal class ObjBase
{
}
internal class Obj : ObjBase
{
}
internal class ObjManager
{
internal List<Obj> returnStuff()
{
return getSomeStuff() as List<Obj>;
}
private List<ObjBase> getSomeStuff()
{
return new List<ObjBase>();
}
}
Instead I have to do this:
internal class ObjBase
{
}
internal class Obj : ObjBase
{
}
internal class ObjManager
{
internal List<Obj> returnStuff()
{
List<ObjBase> returnedList = getSomeStuff();
List<Obj> listToReturn = new List<Obj>(returnedList.Count);
foreach (ObjBase currentBaseObject in returnedList)
{
listToReturn.Add(currentBaseObject as Obj);
}
return listToReturn;
}
private List<ObjBase> getSomeStuff()
{
return new List<ObjBase>();
}
}
I get the following error in Visual Studio 2008 (shortened for readability):
Cannot convert type 'List' to 'List' via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
Thanks.
You can use Cast and ToList extension methods from System.Linq to have this in one line.
Instead of
internal List<Obj> returnStuff()
{
return getSomeStuff() as List<Obj>;
}
do this:
internal List<Obj> returnStuff()
{
return getSomeStuff().Cast<Obj>().ToList();
}
I can only describe the "problem" from a Java view, but from what little I know this aspect is the same in both C# and Java:
A List<ObjBase> is not a List<Obj>, because it could contain an ObjBase object which is not a Obj object.
The other way around a List<Obj> can not be cast to a List<ObjBase> because the former guarantees to accept an Add() call with a ObjBase argument, which the latter will not accept!
So to summarize: even though a Obj is-a ObjBase a List<Obj> is not a List<ObjBase>.
Please look at the following questions:
.NET Casting Generic List
Why does this generic cast fail?
Covariance my friend.
Look at http://blog.t-l-k.com/dot-net/2009/c-sharp-4-covariance-and-contravariance
list.ConvertAll looks tempting but has 1 big disadvantage: it will create a whole new list. This will impact performance and memory usage especially for big lists.
With a bit more effort you can create a wrapper list class that keeps the original list as an internal reference, and convert the items only when they are used.
Usage:
var x = new List<ObjBase>();
var y = x.CastList<ObjBase, Obj>(); // y is now an IList<Obj>
Code to add to your library:
public static class Extensions
{
public static IList<TTo> CastList<TFrom, TTo>(this IList<TFrom> list)
{
return new CastedList<TTo, TFrom>(list);
}
}
public class CastedList<TTo, TFrom> : IList<TTo>
{
public IList<TFrom> BaseList;
public CastedList(IList<TFrom> baseList)
{
BaseList = baseList;
}
// IEnumerable
IEnumerator IEnumerable.GetEnumerator() { return BaseList.GetEnumerator(); }
// IEnumerable<>
public IEnumerator<TTo> GetEnumerator() { return new CastedEnumerator<TTo, TFrom>(BaseList.GetEnumerator()); }
// ICollection
public int Count { get { return BaseList.Count; } }
public bool IsReadOnly { get { return BaseList.IsReadOnly; } }
public void Add(TTo item) { BaseList.Add((TFrom)(object)item); }
public void Clear() { BaseList.Clear(); }
public bool Contains(TTo item) { return BaseList.Contains((TFrom)(object)item); }
public void CopyTo(TTo[] array, int arrayIndex) { BaseList.CopyTo((TFrom[])(object)array, arrayIndex); }
public bool Remove(TTo item) { return BaseList.Remove((TFrom)(object)item); }
// IList
public TTo this[int index]
{
get { return (TTo)(object)BaseList[index]; }
set { BaseList[index] = (TFrom)(object)value; }
}
public int IndexOf(TTo item) { return BaseList.IndexOf((TFrom)(object)item); }
public void Insert(int index, TTo item) { BaseList.Insert(index, (TFrom)(object)item); }
public void RemoveAt(int index) { BaseList.RemoveAt(index); }
}
public class CastedEnumerator<TTo, TFrom> : IEnumerator<TTo>
{
public IEnumerator<TFrom> BaseEnumerator;
public CastedEnumerator(IEnumerator<TFrom> baseEnumerator)
{
BaseEnumerator = baseEnumerator;
}
// IDisposable
public void Dispose() { BaseEnumerator.Dispose(); }
// IEnumerator
object IEnumerator.Current { get { return BaseEnumerator.Current; } }
public bool MoveNext() { return BaseEnumerator.MoveNext(); }
public void Reset() { BaseEnumerator.Reset(); }
// IEnumerator<>
public TTo Current { get { return (TTo)(object)BaseEnumerator.Current; } }
}
I think you are misunderstanding the cast you are trying to do. You are thinking that you are changing the type of the object that is stored in the list, where you are actually trying to change the type of the list itself. It rather makes sense that you can't change the list itself as you have already populated it.
You might look at it as a list of a base class and then cast it when you are processing the list items, that would be my approach.
What is the purpose of this attempted cast?
C# currently does not support variance for generic types. From what I've read, this will change in 4.0.
See here for more information on variance in generics.
Linq has a ConvertAll method. so something like
list.ConvertAll<Obj>(objBase => objbase.ConvertTo(obj));
I'm not sure what else to suggest. I assume ObjBase is the base class, and if all ObjBase objects are Obj objects, i'm not sure why you would have the two objects in the first place. Perhaps i'm off the mark.
Edit: the list.Cast method would work better than the above, assuming they are castable to each other. Forgot about that until I read the other answers.
This is a major pain in C# - this is how generics were designed. List doesn't extend List, its just a completely different type. You can't cast or assign them to each other in any way, your only option is to copy one list to the other one.
Lazarus:
I thought that the compiler would realise that I wanted actions done on the objects of the list and not that I was trying to cast the list itself.
Some more information:
public abstract class ObjBase
{
}
internal interface IDatabaseObject
{
}
public class Obj : ObjBase, IDatabaseObject
{
}
internal interface IDatabaseObjectManager
{
List<ObjBase> getSomeStuff();
}
public class ObjManager : IObjManager
{
public List<Obj> returnStuff()
{
return getSomeStuff().Cast <Customer>().ToList<Customer>();
}
private List<ObjBase> getSomeStuff()
{
return new List<ObjBase>();
}
}
Now client code outside of this DLL can go:
ObjManager objM = new ObjManager();
List listOB = objM.returnStuff();
I'm going to be creating several Obj and ObjManager types for this part (O/RM) of the application.
(Darn comment block ran out of characters! :-)
Here is how I fixed the Conversion from a
list<SomeOtherObject>
to a
object
and then to a
List<object>
https://stackoverflow.com/a/16147909/2307326
Lets say I have this class:
class MyList<T>
{
}
What must I do to that class, to make the following possible:
var list = new MyList<int> {1, 2, 3, 4};
Have an Add method and implement IEnumerable.
class MyList<T> : IEnumerable
{
public void Add(T t)
{
}
public IEnumerator GetEnumerator()
{
//...
}
}
public void T()
{
MyList<int> a = new MyList<int>{1,2,3};
}
Implementing ICollection on MyList will let the initalizer syntax work
class MyList<T> : ICollection<T>
{
}
Although the bare minimum would be:
public class myList<T> : IEnumerable<T>
{
public void Add(T val)
{
}
public IEnumerator<T> GetEnumerator()
{
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
}
}
ICollection<T> is also good.