无法遍历泛型类型 B 的列表 A(icollection),其中 A 和 B 都实现相同的接口
介绍有点乏味,但只是为了清楚起见!有些人甚至可能从中学到一些东西或获得一些方便的见解.我的问题在底部.我真的希望有人能帮助我!
The intro is a bit tedious, but is just for clearity! Some might even learn something from it or get some handy insights. My question is found at the bottom. I really hope someone can help me!
我有这个界面
public interface IEFEntity
{
object GetPKValue();
bool PKHasNoValue();
}
我所有的自动生成的 EF 类都实现了这个接口并实现了 2 个方法.这是通过使用部分类的单独文件完成的,因此在重新生成 EF 类时实现不会消失.这对于问题并不重要,但我在下面给出了两个 EF 类的设置示例,debiteur
和 schakeling
.所有都在同一个命名空间offcourse:
All my automatic genereted EF classes implement this interface and implement the 2 methods. This is done via a separate file using partial classes so the implementation is not gone when regenerating the EF classes. This is not important for the question but I have put an example of the setup of two EF classes, debiteur
and schakeling
below. All are in the same namespace offcourse:
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; }
}
我有这两个额外的部分来实现接口.这里没什么特别的.
And I have this 2 extra partials that implement the interface. Nothing special here.
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 生成的类可能具有名称不是id"的 PK 属性,或者甚至具有字符串类型的 PK 和用户名的名称,但这对于问题并不重要!而且也不是我使用这些方法的唯一原因,请继续阅读...)
我有一个使用两个泛型类型参数的 GenManager 类.这是没有实现的类定义.(而且我知道,这仅适用于具有单个 PK 而非复合键的实体/表,正如争论的那样 这里)
I have a GenManager class which uses two generic type parameters. Here's the class definition without implementation. (And I know, this only works for entities/tables with a single PK not with composite keys, as debated here)
public class GenManager<Entity, EntityKey> where Entity : class, IEFEntity {}
这意味着实体类型参数必须是实现接口 IEFEntity 的类.所以在我的应用程序中的任何地方,假设我现在可以使用以下控制器创建一个实例:
This means that the Entity type parameter must be a class which implement interface IEFEntity. So anywhere in my application, lets say a controller I can now create an instance by using:
private GenManager<debiteur, int> DebiteurManager;
private GenManager<schakeling, int> SchakelingManager;
但例如:
private GenManager<anotherClass, int> AnotherClassManager;
会失败,因为 anotherClass
没有实现 IEFEntity.但是回到 GenManager 类.这是没有所有实现的第一个大纲
will fail because anotherClass
does not implement IEFEntity. But back to the GenManager class. Here's the first outlining without all the implementation
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 { }
}
花点时间看看这个.正如GenManager
类的第一个泛型类型Entity
必须是一个实现了IEFEntity
的类,这也必须是泛型类型FKEntity
在方法中使用.例如,在我的控制器中,我现在可以使用以下语句:
Take a second to look at this. Just as the first generic type Entity
of the GenManager
class must be a class that implements IEFEntity
, this must also be the case with generic type FKEntity
used in the methods. So in my controller for example I can now use this statement:
bool b = DebiteurManager.isInFKEntity<schakeling, int>(debiteur_id, schakeling_id);
还是举个例子:
bool b = DebiteurManager.isInFKEntity<anotherEntity, int>(debiteur_id, anotherEntity_id);
会失败,因为 anotherEntity
没有实现 IEFEntity.
will fail because anotherEntity
does not implement IEFEntity.
而正是在这些方法中,必须使用 c# 反射才能产生奇迹,而我面临一个问题.我给你未完成的方法 isInFKEntity 的实现和一些测试代码语句,包括注释:
And it is in these methods where the magic must happen using c# reflection and I face a problem. I give you the implementation of the unfinished method isInFKEntity with some test code statements including comments:
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 语句无法对object"类型的变量进行操作,因为object"不包含'GetEnumerator' 的公共定义.此外,使用智能感知仅显示 4 个标准方法 Equals(object obj)、GetHashCode()、GetType() 和 ToString().见图片
I want to loop through FKEntityList
but if I try to do that using a foreach I get a message: foreach statement cannot operate on variables of type 'object' because 'object' does not contain a public definition for 'GetEnumerator'. Also, using intellisense only shows the 4 standard methods Equals(object obj), GetHashCode(), GetType() and ToString(). See image
所以我尝试使用 as List
成功地将它投射并将结果分配给 FKEntityListWithCast
,现在我使用 foreach 没有收到错误消息.
So I try to cast it succesfully using as List<FKEntity>
and assign the result to FKEntityListWithCast
and now I get no error message using a foreach.
所以我想,很好,我只使用这个 return 语句并且它有效:
So I thought, very nice I just use this return statement and it works:
return FKEntityListWithCast.Any(item => item.GetPKValue().ToString() == fk.ToString());
上面的 return 语句没有给出错误并且一切都编译,但问题是在运行时 FKEntityListWithCast
没有得到值.它保持NULL.所以问题是:
The above return statment doesn't give an error and everything compiles, but the problem is that at runtime the FKEntityListWithCast
doesn't get a value. It stays NULL. So the problem is:
在运行时获取值但不能循环:
GETS VALUE at runtime but CANNOT loop through:
var FKEntityList = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry);
在运行时获取无值(NULL)但可以循环:
GETS NO VALUE(NULL) at runtime but CAN loop through:
var FKEntityListWithCast = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry) as List<FKEntity>;
任何帮助都会非常有用!
Any help would be greatly appiciated!
ICollection<FKEntity> FKEntityList = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry) as ICollection<FKEntity>;
还是很无语,没人能回答这个问题
Still a bummer nobody could answer this