无法遍历泛型类型B的列表A(icollection),其中A和B都实现相同的接口

时间:2015-06-16 11:30:20

标签: generics interface repository system.reflection .net-4.5.2

介绍有点乏味,但只是为了清晰!有些人甚至可能从中学到一些东西或获得一些方便的见解。我的问题在底部找到。我真的希望有人可以帮助我!

我有这个界面

public interface IEFEntity
{
    object GetPKValue();
    bool PKHasNoValue();
}

我所有自动生成的EF类都实现了这个接口并实现了2种方法。这是通过使用部分类的单独文件完成的,因此在重新生成EF类时实现不会消失。这对于这个问题并不重要,但我在下面列举了两个EF类debiteurschakeling的设置示例。所有这些都在同一名称空间中:

public partial class debiteur
    {
        public debiteur()
        {
            this.schakeling = new HashSet<schakeling>();
        }

        public int id { get; set; }
        public string naam { get; set; }

        public virtual ICollection<schakeling> schakeling { get; set; }
    }
public partial class schakeling
    {
        public schakeling()
        {
            this.debiteur = new HashSet<debiteur>();
        }

        public int id { get; set; }
        public string omschrijving { get; set; }

        public virtual ICollection<debiteur> debiteur { get; set; }
    }

我有两个实现界面的额外部分。这里没什么特别的。

public partial class debiteur : IEFEntity
    {
        public object GetPKValue() {
            return this.id;
        }

        public bool PKHasNoValue() {
            return this.id == 0;
        }
    }
public partial class schakeling : IEFEntity
    {
        public object GetPKValue() {
            return this.id;
        }

        public bool PKHasNoValue() {
            return this.id == 0;
        }
    }

(只是为了澄清:其他EF生成的类可能有一个PK属性,其名称不是&#39; id&#39;或者甚至有一个类型为字符串的PK和一个用户名,但这对于这个问题并不重要!而且这也不是我使用这些方法的唯一原因,请继续阅读......)

我有一个GenManager类,它使用两个泛型类型参数。这是没有实现的类定义。 (我知道,这只适用于具有单个PK的实体/表,而不是复合键,如有争议的here

public class GenManager<Entity, EntityKey> where Entity : class, IEFEntity {}

这意味着Entity类型参数必须是实现接口IEFEntity的类。所以在我的应用程序的任何地方,让我们说一个控制器我现在可以使用:

创建一个实例
private GenManager<debiteur, int> DebiteurManager;
private GenManager<schakeling, int> SchakelingManager;

但是例如:

private GenManager<anotherClass, int> AnotherClassManager;

将失败,因为anotherClass未实现IEFEntity。但是回到GenManager类。这是第一个没有所有实现的概述

public class GenManager<Entity, EntityKey> where Entity : class, IEFEntity
    {
        public IQueryable<Entity> Items { get { return repo.Items; } }
        private IGenRepo<Entity, EntityKey> repo;

        public GenManager(IGenRepo<Entity, EntityKey> repo) { this.repo = repo; }

        public Entity find(EntityKey pk) { return repo.find(pk); }
        public RepoResult delete(EntityKey pk) { return repo.delete(pk); }
        public RepoResult create(Entity item) { return repo.create(item); }
        public RepoResult update(Entity item) { return repo.update(item); }

        public bool isInFKEntity<FKEntity, FKEntityKey>(EntityKey pk, FKEntityKey fk) where FKEntity : class, IEFEntity { }

        public List<FKEntity> GetFKEntities<FKEntity, FKEntityKey>(EntityKey pk) where FKEntity : IEFEntity { }

        public RepoResult removeFKEntities<FKEntity, FKEntityKey>(EntityKey pk, FKEntityKey[] fkList) where FKEntity : IEFEntity { }

        public RepoResult addFKEntities<FKEntity, FKEntityKey>(EntityKey pk, FKEntityKey[] fkList) where FKEntity : IEFEntity { }

        public RepoResult resetFKEntities<FKEntity, FKEntityKey>(EntityKey pk, FKEntityKey[] fkList) where FKEntity : IEFEntity { }

        public RepoResult resetFKEntities2<FKEntity, FKEntityKey>(EntityKey pk, FKEntityKey[] fkList) where FKEntity : IEFEntity { }

        public RepoResult resetFKEntities3<FKEntity, FKEntityKey>(EntityKey pk, FKEntityKey[] fkList) where FKEntity : IEFEntity { }

        public RepoResult clearFKEntities<FKEntity>(EntityKey pk) where FKEntity : IEFEntity { }
    }

花点时间看看这个。正如Entity类的第一个泛型类型GenManager必须是实现IEFEntity的类一样,这也必须是方法中使用的泛型类型FKEntity的情况。所以在我的控制器中,我现在可以使用这个语句:

bool b = DebiteurManager.isInFKEntity<schakeling, int>(debiteur_id, schakeling_id);

但又是一个例子:

bool b = DebiteurManager.isInFKEntity<anotherEntity, int>(debiteur_id, anotherEntity_id);

将失败,因为anotherEntity未实现IEFEntity。

正是在这些方法中,使用c#反射必须发生魔法并且我遇到了问题。我给你执行未完成的方法isInFKEntity,其中包含一些测试代码语句,包括注释:

public bool isInFKEntity<FKEntity, FKEntityKey>(EntityKey pk, FKEntityKey fk) where FKEntity : class, IEFEntity
    {
        Entity dbEntry = find(pk);
        if (dbEntry == null) throw new InvalidOperationException(RepoMessages.dbEntryIsNull(new List<object> { pk }));

        //----------Not important for question! Just to clearify things----------\\
        var v1 = typeof(Entity).GetProperty("naam").GetValue(dbEntry);//Sets v1 to a string value
        var v1Copy = new debiteur().GetType().GetProperty("naam").GetValue(dbEntry);//Just to test and clearify what the above statement does, vars have the same value!
        //----------End----------\\

        var FKEntityList = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry);//Gives a list back at runtime, but I can't loop through them
        var FKEntityListCopy = new debiteur().GetType().GetProperty("schakeling").GetValue(dbEntry);//Just to test and clearify what the above statement does, vars have the same value!

        var FKEntityListWithCast = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry) as List<FKEntity>;//Gives a NULL value back at runtime, but intellisense!
        var FKEntityListWithCastCopy = new debiteur().GetType().GetProperty("schakeling").GetValue(dbEntry) as List<FKEntity>;//Just to test and clearify what the above statement does, vars have the same value!(also NULL)

        return false;
    }

我想循环遍历FKEntityList但如果我尝试使用foreach这样做,我会得到一条消息:foreach语句不能对类型&#39; object&#39;的变量进行操作。因为&#39;对象&#39;不包含&#39; GetEnumerator&#39;的公开定义。此外,使用intellisense仅显示4种标准方法Equals(object obj),GetHashCode(),GetType()和ToString()。见image

所以我尝试使用as List<FKEntity>成功地投射它并将结果分配给FKEntityListWithCast,现在我没有使用foreach获得错误消息。

所以我想,非常好我只是使用这个return语句并且它有效:

return FKEntityListWithCast.Any(item => item.GetPKValue().ToString() == fk.ToString());    

上述返回语句不会出错并且所有内容都会编译,但问题是在运行时FKEntityListWithCast没有得到值。它保持为NULL。所以问题是:

在运行时获取值但不能循环:

var FKEntityList = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry);

在运行时没有值(NULL)但CAN循环:

var FKEntityListWithCast = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry) as List<FKEntity>;

任何帮助都会受到极大的关注!

1 个答案:

答案 0 :(得分:0)

ICollection<FKEntity> FKEntityList = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry) as ICollection<FKEntity>;

仍然无人能回答这个问题