为什么我不能将EntityCollection <tentity>转换为ICollection <object>?</object> </tentity>

时间:2014-03-06 10:08:07

标签: c# entity-framework generics

如果我尝试将EntityCollection<MyNamespace.Models.MyEntityClass>类型的对象转换为ICollection<Object>,我会得到InvalidCastException

好的,根据文档,EntityCollection<TEntity>实现了ICollection<T>,而MyNamespace.Models.MyEntityClass必须来自Object,对吧?那么为什么这会失败呢?

FWIW,我正在尝试通过一种方法来执行此操作,该方法通常可以添加和删除可能是EntityCollection或其他IListISet的内容中的项目。我需要保留EntityCollection的更改跟踪行为,因为如果它是EC,该对象最终将能够提交更改。

修改

好的,这里有一些我正在做的具体细节。我正在反序列化JSON,并且目标对象可以具有集合的属性 - 可能它们是EntityCollection,也许不是。为了简单起见,我们假设集合的成员总是EntityObject的子类,无论它是EntityCollection还是没有(如果我理解到目前为止的反应,我没有更好的运气铸造到ICollection<EntityObject>而不是ICollection<Object> ......对吗?)。这是我遇到麻烦的部分......

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
            }
        }

    }

}

这有点简化,我有Arrays的特殊情况(实现ICollection,但不是泛型)和我拿出的其他东西。重点是,我需要在Clear本身上操作AddRemoveEntityCollection - 如果它就是这样的话。也许还有另一种方法来进行我缺少的这种同步?

2 个答案:

答案 0 :(得分:1)

由于ICollection<T>没有差异,ICollection<MyEntityClass>ICollection<object>是不同的类型,彼此无关。

  

我正在尝试通常可以添加和删除的方法中执行此操作   来自可能是EntityCollection或其他IList或者的项目   的ISet

那么,你为什么不与IList合作?看起来你并不关心这种方法中真实的物品类型。

答案 1 :(得分:1)

读写集合不能是变体。

举个例子:

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>!

原则上,这种类型的转换只适用于“只读”接口(允许协方差)或“只写”接口(允许相反)。

一个“解决方案”将涉及这样的包装类:

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();
    }
}

而不是

 EntityCollection<MyNamespace.Models.MyEntityClass> collection = ...;
 ICollection<Object> generic = collection ;

你必须写:

 EntityCollection<MyNamespace.Models.MyEntityClass> collection = ...;
 ICollection<Object> generic = new Wrapper(collection);

并且可以在注释标记的点处调整包装类,如何处理类型问题。