Why can't I cast EntityCollection<TEntity> to ICollection<Object>? - c#

If I try to cast an object of type EntityCollection<MyNamespace.Models.MyEntityClass> to ICollection<Object> I get an InvalidCastException.
Okay, according to the docs, EntityCollection<TEntity> implements ICollection<T>, and MyNamespace.Models.MyEntityClass must descend from Object, right? So why on earth does this fail?
FWIW, I'm trying to do this in a method that generally can add and remove items from what might be an EntityCollection or some other IList or ISet. I need to preserve the change tracking behavior of EntityCollection, because the object is to eventually be able to commit the changes if it's an EC.
Edit
Okay, here's some more specifics of what I'm doing. I'm deserializing JSON, and the target object can have properties that are collections--maybe they're EntityCollections, maybe not. For the sake of simplicity, lets say the members of the collection are always subclasses of EntityObject, whether it's an EntityCollection or not (if I understand the responses so far, I'd have no better luck casting to ICollection<EntityObject> than to ICollection<Object>…right?). This is the part where I run into trouble…
foreach (PropertyInfo prop in hasManys)
{
// This is where I get the InvalidCastException...
ICollection<Object> oldHms = (ICollection<Object>)prop.GetValue(parentObj, null);
JEnumerable<JToken> hmIds = links[FormatPropName(prop.Name)].Children();
if (hmIds.Count() == 0)
{
// No members! Clear it out!
oldHms.Clear();
continue; // breaking early!
}
relType = prop.PropertyType.GetGenericArguments()[0];
// Get back the actual entities we'll need to put into the relationship...
List<EntityObject> newHms = new List<EntityObject>();
foreach (JToken jt in hmIds)
{
// ...populate newHms with existing EntityObjects from the context...
}
// first, delete any missing...
/* Got to use ToList() to make a copy, because otherwise missings is
* still connected to the oldHms collection (It's an ObjectQuery)
* and you can't modify oldHms while enumerating missings.
*/
// This cast will fail too, right? Though it's more easily fixable:
IEnumerable<EntityObject> missings = ((ICollection<EntityObject>)oldHms).Except(newHms).ToList();
foreach (EntityObject missing in missings)
{
oldHms.Remove(missing); // One of my mutable collection operations
}
// add new ones
foreach (EntityObject child in newHms)
{
if (!oldHms.Contains(child)) // Skip if already in there
{
oldHms.Add(child); // another mutable collection operation
}
}
}
}
That's a bit simplified, I have special cases for Arrays (implement ICollection, but aren't generics) and other stuff that I took out. Point is, I need to operate Clear, Add, and Remove on the EntityCollection itself--if that's what it is. Maybe there's another way to do this type of synchronization that I'm missing?

read-write collections cannot be variant.
Take this example:
List<MyClass> list1 = new List<MyClass>();
// assume this would work
ICollection<object> list2 = list1;
list2.Add(new object()); // ooops. We added an object to List<MyClass>!
In principal this kind of casting is only possible for "read-only" interfaces (allowing covariance) or for "write-only" interfaces (allowing contravariance).
One "solution" would involve a wrapper class like this:
public class Wrapper<T> : ICollection<object>
{
private readonly ICollection<T> collection;
public Wrapper(ICollection<T> collection)
{
this.collection = collection;
}
public void Add(object item)
{
// maybe check if T is of the desired type
collection.Add((T)item);
}
public void Clear()
{
collection.Clear();
}
public bool Contains(object item)
{
// maybe check if T is of the desired type
return collection.Contains((T)item);
}
public void CopyTo(object[] array, int arrayIndex)
{
// maybe check if T is of the desired type
collection.CopyTo(array.Cast<T>().ToArray(), arrayIndex);
}
public int Count
{
get { return collection.Count; }
}
public bool IsReadOnly
{
get { return collection.IsReadOnly; }
}
public bool Remove(object item)
{
// maybe check if T is of the desired type
return collection.Remove((T)item);
}
public IEnumerator<object> GetEnumerator()
{
yield return collection;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return collection.GetEnumerator();
}
}
Instead of
EntityCollection<MyNamespace.Models.MyEntityClass> collection = ...;
ICollection<Object> generic = collection ;
you would have to write:
EntityCollection<MyNamespace.Models.MyEntityClass> collection = ...;
ICollection<Object> generic = new Wrapper(collection);
And could adjust the wrapper class at the points marked by comments how to deal with type problems.

Since ICollection<T> hasn't variance, ICollection<MyEntityClass> and ICollection<object> are different types, unrelated to each other.
I'm trying to do this in a method that generally can add and remove
items from what might be an EntityCollection or some other IList or
ISet
So, why don't you work with IList? Looks like you don't care about real type of items in this method.

Related

Cast type as specific MyCollection<MyType> and call method on it via Reflection

I have a custom collection type ObservableStateCollection that, for simplistic purposes, looks like:
public class ObservableStateCollection<T> : IList<T>, INotifyCollectionChanged, INotifyPropertyChanged where T : StateObservable
{
private List<T> _items;
private List<T> _deleted;
public IEnumerator<T> GetEnumerator()
{
return _items.GetEnumerator();
}
public IEnumerable<StateObservable> GetAll()
{
return _items.Concat(_deleted);
}
//...
}
Note that type T must be derived from StateObservable.
Now, I'm neck deep in reflection. I'll spare the details of 'why', and just show you where I'm currently at. I need to check if a particular property on my model is an ObservableStateCollection<T> and use a foreach to loop through the GetAll() method.
Currently, I'm at:
if(prop.PropertyType.GetGenericTypeDefinition() == typeof(ObservableStateCollection<>))
{
var collection = (ObservableStateCollection<StateObservable>)prop.GetValue(model, null);
foreach (var e in collection.GetAll())
{
//act on ObservableStateCollection<StateObservable>
}
}
which throws an exception on the line var collection = ..., as I can't cast ObservableStateCollection<DerivedType> to ObservableStateCollection<BaseType>
What are my options here? How to I get a strongly typed object back that I can call GetAll on?
ahh got it. I invoked GetAll via reflection. Not sure why that didn't occur to me at first:
if(prop.PropertyType.GetGenericTypeDefinition() == typeof(ObservableStateCollection<>))
{
MethodInfo m = prop.PropertyType.GetMethod("GetAll");
var collection = m.Invoke(prop.GetValue(model, null), null);
foreach (var e in (IEnumerable)collection)
{
\\act on item in collection
}
}

How to Ensure Immutability of a Generic

This example is in C# but the question really applies to any OO language. I'd like to create a generic, immutable class which implements IReadOnlyList. Additionally, this class should have an underlying generic IList which is unable to be modified. Initially, the class was written as follows:
public class Datum<T> : IReadOnlyList<T>
{
private IList<T> objects;
public int Count
{
get;
private set;
}
public T this[int i]
{
get
{
return objects[i];
}
private set
{
this.objects[i] = value;
}
}
public Datum(IList<T> obj)
{
this.objects = obj;
this.Count = obj.Count;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return this.objects.GetEnumerator();
}
}
However, this isn't immutable. As you can likely tell, changing the initial IList 'obj' changes Datum's 'objects'.
static void Main(string[] args)
{
List<object> list = new List<object>();
list.Add("one");
Datum<object> datum = new Datum<object>(list);
list[0] = "two";
Console.WriteLine(datum[0]);
}
This writes "two" to the console. As the point of Datum is immutability, that's not okay. In order to resolve this, I've rewritten the constructor of Datum:
public Datum(IList<T> obj)
{
this.objects = new List<T>();
foreach(T t in obj)
{
this.objects.Add(t);
}
this.Count = obj.Count;
}
Given the same test as before, "one" appears on the console. Great. But, what if Datum contains a collection of non-immutable collection and one of the non-immutable collections is modified?
static void Main(string[] args)
{
List<object> list = new List<object>();
List<List<object>> containingList = new List<List<object>>();
list.Add("one");
containingList.Add(list);
Datum<List<object>> d = new Datum<List<object>>(containingList);
list[0] = "two";
Console.WriteLine(d[0][0]);
}
And, as expected, "two" is printed out on the console. So, my question is, how do I make this class truly immutable?
You can't. Or rather, you don't want to, because the ways of doing it are so bad. Here are a few:
1. struct-only
Add where T : struct to your Datum<T> class. structs are usually immutable, but if it contains mutable class instances, it can still be modified (thanks Servy). The major downside is that all classes are out, even immutable ones like string and any immutable class you make.
var e = new ExtraEvilStruct();
e.Mutable = new Mutable { MyVal = 1 };
Datum<ExtraEvilStruct> datum = new Datum<ExtraEvilStruct>(new[] { e });
e.Mutable.MyVal = 2;
Console.WriteLine(datum[0].Mutable.MyVal); // 2
2. Create an interface
Create a marker interface and implement it on any immutable types you create. The major downside is that all built-in types are out. And you don't really know if classes implementing this are truly immutable.
public interface IImmutable
{
// this space intentionally left blank, except for this comment
}
public class Datum<T> : IReadOnlyList<T> where T : IImmutable
3. Serialize!
If you serialize and deserialize the objects that you are passed (e.g. with Json.NET), you can create completely-separate copies of them. Upside: works with many built-in and custom types you might want to put here. Downside: requires extra time and memory to create the read-only list, and requires that your objects are serializable without losing anything important. Expect any links to objects outside of your list to be destroyed.
public Datum(IList<T> obj)
{
this.objects =
JsonConvert.DeserializeObject<IList<T>>(JsonConvert.SerializeObject(obj));
this.Count = obj.Count;
}
I would suggest that you simply document Datum<T> to say that the class should only be used to store immutable types. This sort of unenforced implicit requirement exists in other types (e.g. Dictionary expects that TKey implements GetHashCode and Equals in the expected way, including immutability), because it's too difficult for it to not be that way.
Kind of hacky, and definitely more confusing than it's worth in my opinion, but if your T is guaranteed to be serializable, you can store string representations of the objects in your collection rather than storing the objects themselves. Then even if someone pulls an item from your collection and modifies it, your collection would still be intact.
It would be slow and you'd get a different object every time you pulled it from the list. So I'm not recommending this.
Something like:
public class Datum<T> : IReadOnlyList<T>
{
private IList<string> objects;
public T this[int i] {
get { return JsonConvert.DeserializeObject<T>(objects[i]); }
private set { this.objects[i] = JsonConvert.SerializeObject(value); }
}
public Datum(IList<T> obj) {
this.objects = new List<string>();
foreach (T t in obj) {
this.objects.Add(JsonConvert.SerializeObject(t));
}
this.Count = obj.Count;
}
public IEnumerator<T> GetEnumerator() {
return this.objects.Select(JsonConvert.DeserializeObject<T>).GetEnumerator();
}
}
It's impossible. There's no possible way to constrain the generic type to be immutable. The best that you can possibly do is write a collection that cannot allow the structure of that collection to be modified. There is no way to prevent the collection from being used as a collection of some mutable type.
think that such collections are not match OOP, because this design leads to specific co-relation between independent classes - collection and it's items. How one class can change behavior of other without knowlege of each other?
So suggestions of serialization and so can allow you to do it on hacky way, but better is to decide if it's so required to make collection of immutable items, who trys to change them except your own code? May be better "to not mutate" items rather than try "make them immutable".
I faced the same problem, where I implement an object (say CachedData<T>) which handles a cached copy of the property of another object (say T SourceData). When calling the constructor of CachedData, you pass a delegate which returns a SourceData. When calling CachedData<T>.value, you get a copy of SourceData, which is updated every now and then.
It would make no sense to try caching an object, as .Value would only cache the reference to the data, not the data itself. It would only make sense to cache data types, strings, and perhaps structures.
So I ended up:
Thoroughly documenting CachedData<T>, and
Throwing an error in the constructor if T is neither a ValueType, a Structure, or a String. Some like (forgive my VB): If GetType(T) <> GetType(String) AndAlso GetType(T).IsClass Then Throw New ArgumentException("Explain")

Convert List<T> to List<object>

I have a problem with the generic class. I have something like this:
public abstract class IGroup<T> : IEnumerable where T : class {
protected List<T> groupMembers;
protected List<IGameAction> groupIGameActionList;
public IGroup() {
groupMembers = new List<T>();
groupIGameActionList = new List<IGameAction>();
//groupIGameActionList.Add(new DieGameAction(groupMembers));
}
}
And second class:
class DieGameAction : IGameAction {
List<object> gameObjectList;
public DieGameAction(List<object> objectList) {
gameObjectList = objectList;
}
}
I don't know how to cast or convert groupMembers in commented line. This doesn't work because it can not be converted (List<T> to List<object>). So how can I do it?
groupMembers.Cast<object>().ToList();
But that doesn't look a good thing to do. You are creating a new empty list that will not be related to the original anymore.
The way you're gonna be using these classes will tell if that would be a good idea.
If you're planning to have both lists updated by adding items to a single class, it will not fit. Then maybe your DieGameAction should be generic as well: DieGameAction<T>.
Then you could give the original list without casting.
But, there's another danger: if you set a new list to the IGroup, it will not be reflected to DieGameAction.
So, it all depends on what you're trying to do.
Old question but by declaring your variable as IList instead of List<object>, you can assign a list (or array) of any type to the variable and simply cast it to List<Whatever> later (of course it's going to throw an exception if you cast it to a wrong type). I have found this more efficient than having to do .Cast<object>() every time you want to assign something to the variable.
I'm going to focus only on providing a solution.
You can make DieGameAction use IList < object > instead:
class DieGameAction : IGameAction {
IList<object> gameObjectList;
public DieGameAction(IList<object> objectList) {
gameObjectList = objectList;
}
}
Then you can provide an IList < object > implementation which adapts any IList < T >.
public abstract class IGroup<T> : IEnumerable where T : class {
protected List<T> groupMembers;
protected List<IGameAction> groupIGameActionList;
public IGroup() {
groupMembers = new List<T>();
groupIGameActionList = new List<IGameAction>();
groupIGameActionList.Add(new DieGameAction(new ObjectListAdapter<T>(groupMembers)));
}
}
I'm going to try and provide one of the many possible solutions using as base the System.Collections.ObjectModel.Collection < T > which can also wrap an IList < T >:
public class ObjectListAdapter<T> : System.Collections.ObjectModel.Collection<T>, IList<object>
{
public ObjectListAdapter(IList<T> wrappedList)
: base(wrappedList)
{
}
public int IndexOf(object item)
{
return base.IndexOf((T)item);
}
public void Insert(int index, object item)
{
base.Insert(index, (T)item);
}
public new object this[int index]
{
get
{
return base[index];
}
set
{
base[index] = (T)value;
}
}
public void Add(object item)
{
base.Add((T)item);
}
public bool Contains(object item)
{
return base.Contains((T)item);
}
public void CopyTo(object[] array, int arrayIndex)
{
this.Cast<object>().ToArray().CopyTo(array, arrayIndex);
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(object item)
{
return base.Remove((T)item);
}
public new IEnumerator<object> GetEnumerator()
{
return this.Cast<object>().GetEnumerator();
}
}
The list changes will throw a type casting exception upon trying to use an unsupported object, the way I programmed it over here, but you can also handle that as you like.
Now, for IList < object > you could also try using IList instead which is also implemented by List < T > so you'll basically have to do nothing more to get this working.
Note that the important thing is that the list will appear the same at both places used since they will basically be using the same underlying List object.
Let me know if this answers your question, by marking it as an answer, or not to refrain :)
I just faced the same problem which led me here. The solution that worked for me was to cast into IEnumerable of Object instead of List of Object
(System.Collections.Generic.IEnumerable<object>)groupMembers;
I had similar issue today but i called the LINQ .ToArray() on it directly and it works fine. that should be shorter than casting.
so you could say
groupMembers.ToArray();
It worked for me like this:
List<myclass> listMyclass = new List<myclass>();
var listObject = listMyclass.ToList<object>();

list.ToArray vs list

I noticed something strange and there is a possibility I am wrong.
I have an interface IA and class A:
interface IA { .... }
class A : IA { .... }
In other class I have this:
private IList<A> AList;
public IList<IA> {
get { return AList; }
}
But I get compilation error.
But if I change it to:
public IList<IA> {
get { return AList.ToArray(); }
}
Everything is fine.
Why is it?
Why this doesn't work
private IList<A> AList;
public IList<IA> { get { return AList; } }
Exposing the property as IList<IA> would allow you to try to add class B : IA to the list, but the underlying list is really IList<A>, B is not A, so this would blow up in your face. Thus, it is not allowed.
Why this works:
public IList<IA> { get { return AList.ToArray(); } }
Array variance is broken. You can return the list as an array, it will still blow up in your face at runtime if you tried an Add operation (or try to replace an object at a given index with something other than an object of type A, but it's legal at compile time. A different example of this variance at play:
string[] array = new string[10];
object[] objs = array; // legal
objs[0] = new Foo(); // will bite you at runtime
From comments:
So what you suggest to use? How can I make the property return valid
object? How can I make the return value read only?
If consumers only need to iterate over the sequence and not have random, indexed access to it, you can expose the property as an IEnumerable<IA>.
public IEnumerable<IA> TheList
{
get { return AList.Select(a => a); }
}
(The Select is actually not technically needed, but using this will prevent consumers from being able to cast the result to its true underlying List<> type.) If the consumers decide they want a list or an array, they are free to call ToList() or ToArray() on it, and whatever they do with it (in terms of adding, removing, replacing items) will not affect your list. (Changes to the items' properties would be visible.) Similarly, you could also expose the collection an IList<IA> yourself in a safe way
public IList<IA> TheList
{
get { return AList.ToList<IA>(); }
}
Again, this would return a copy of the list, so any changes to it would not affect your underlying list.
Because native arrays are broken. This code is bad, you shouldn't do it, and the C# designers wish desperately they could undo it.
Arrays are covariant but lists are not.

Generic method to create deep copy of all elements in a collection

I have various ObservableCollections of different object types. I'd like to write a single method that will take a collection of any of these object types and return a new collection where each element is a deep copy of elements in the given collection. Here is an example for a specifc class
private static ObservableCollection<PropertyValueRow> DeepCopy(ObservableCollection<PropertyValueRow> list)
{
ObservableCollection<PropertyValueRow> newList = new ObservableCollection<PropertyValueRow>();
foreach (PropertyValueRow rec in list)
{
newList.Add((PropertyValueRow)rec.Clone());
}
return newList;
}
How can I make this method generic for any class which implements ICloneable?
You could do something like this:
private static ObservableCollection<T> DeepCopy<T>(ObservableCollection<T> list)
where T : ICloneable
{
ObservableCollection<T> newList = new ObservableCollection<T>();
foreach (T rec in list)
{
newList.Add((T)rec.Clone());
}
return newList;
}
Note that you could make this more general by taking IEnumerable<T>, and LINQ makes it even easier:
private static ObservableCollection<T> DeepCopy<T>(IEnumerable<T> list)
where T : ICloneable
{
return new ObservableCollection<T>(list.Select(x => x.Clone()).Cast<T>());
}
private static ObservableCollection<T> DeepCopy<T>(ObservableCollection<T> list)
where T : ICloneable
{
ObservableCollection<T> newList = new ObservableCollection<T>();
foreach (T rec in list)
{
newList.Add((T)rec.Clone());
}
return newList;
}
I use a very similar function which works with all ICollections which can be constructed (e.g. many standard collections):
public static TContainer CloneDeep<TContainer, T>( TContainer r )
where T : ICloneable
where TContainer: ICollection<T>, new()
{
// could use linq here, but this is my original pedestrian code ;-)
TContainer l = new TContainer();
foreach(var t in r)
{
l.Add( (T)t.Clone() );
}
return l;
}
Unfortunately the compiler isn't able to deduce the types so that one must pass them explicitly. For more than a handful calls I write a specialization. Here is an example for Lists (which itself can be called with implicitly deduced T).
public static List<T> CloneListDeep<T>( List<T> r ) where T : ICloneable
{
return CloneDeep<List<T>, T>( r );
}
I use this function extensively in order to create copies of lists serving as datasources for datagridviews on dialogs which can be canceled. The modified list is simply discarded when the dialog is cancelled; when the dialog is OKed the edited list simply replaces the original. Prerequisite for this pattern is, of course, to have a semantically correct and well maintained T.clone().

Categories

Resources