无法遍历泛型 B 的列表 A(icollection),其中 A 和 B 都实现相同的接口
Cannot loop through list A(icollection) of generic type B where A and B both implement same interface
介绍有点乏味,但只是为了清楚起见!有些人甚至可能从中学到一些东西或获得一些方便的见解。我的问题在底部。我真的希望有人能帮助我!
我有这个界面
public interface IEFEntity
{
object GetPKValue();
bool PKHasNoValue();
}
我所有自动生成的 EF classes 都实现了这个接口并实现了 2 个方法。这是通过使用部分 classes 的单独文件完成的,因此在重新生成 EF classes 时实施不会消失。这对于问题并不重要,但我在下面给出了两个 EF classes、debiteur
和 schakeling
的设置示例。所有都在同一个命名空间中:
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; }
}
而且我有这 2 个额外的实现接口的部分。这里没什么特别的。
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 生成的 classes 可能有一个 PK 属性 谁的名字不是 'id' 或者甚至有一个字符串类型的 PK和用户名,但这对问题并不重要!也不是我使用这些方法的唯一原因,请继续阅读...)
我有一个 GenManager class,它使用两个通用类型参数。这是没有实现的 class 定义。 (而且我知道,这仅适用于 entities/tables 使用单个 PK 而不是使用复合键,正如所讨论的 here)
public class GenManager<Entity, EntityKey> where Entity : class, IEFEntity {}
这意味着实体类型参数必须是实现接口 IEFEntity 的 class。因此,在我的应用程序的任何地方,假设一个控制器,我现在可以使用以下方法创建一个实例:
private GenManager<debiteur, int> DebiteurManager;
private GenManager<schakeling, int> SchakelingManager;
但是例如:
private GenManager<anotherClass, int> AnotherClassManager;
将失败,因为 anotherClass
未实现 IEFEntity。但是回到 GenManager class。这是没有所有实现的第一个概述
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
class 的第一个泛型类型 Entity
必须是实现 IEFEntity
的 class,泛型类型 [=] 也必须如此31=] 在方法中使用。所以在我的控制器中,例如我现在可以使用这个语句:
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 语句无法对 'object' 类型的变量进行操作,因为 'object' 会不包含 'GetEnumerator' 的 public 定义。此外,使用智能感知仅显示 4 个标准方法 Equals(object obj)、GetHashCode()、GetType() 和 ToString()。参见 image
所以我尝试使用 as List<FKEntity>
成功转换它并将结果分配给 FKEntityListWithCast
现在我使用 foreach 没有收到任何错误消息。
所以我想,非常好,我只是使用这个 return 语句并且它有效:
return FKEntityListWithCast.Any(item => item.GetPKValue().ToString() == fk.ToString());
上面的 return 语句没有给出错误并且所有内容都可以编译,但问题是在运行时 FKEntityListWithCast
没有得到值。它保持为 NULL。所以问题是:
在运行时获取值但无法循环:
var FKEntityList = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry);
在运行时获取无值(NULL)但可以循环通过:
var FKEntityListWithCast = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry) as List<FKEntity>;
如有任何帮助,我们将不胜感激!
ICollection<FKEntity> FKEntityList = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry) as ICollection<FKEntity>;
仍然是一个无赖,没有人能回答这个问题
介绍有点乏味,但只是为了清楚起见!有些人甚至可能从中学到一些东西或获得一些方便的见解。我的问题在底部。我真的希望有人能帮助我!
我有这个界面
public interface IEFEntity
{
object GetPKValue();
bool PKHasNoValue();
}
我所有自动生成的 EF classes 都实现了这个接口并实现了 2 个方法。这是通过使用部分 classes 的单独文件完成的,因此在重新生成 EF classes 时实施不会消失。这对于问题并不重要,但我在下面给出了两个 EF classes、debiteur
和 schakeling
的设置示例。所有都在同一个命名空间中:
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; }
}
而且我有这 2 个额外的实现接口的部分。这里没什么特别的。
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 生成的 classes 可能有一个 PK 属性 谁的名字不是 'id' 或者甚至有一个字符串类型的 PK和用户名,但这对问题并不重要!也不是我使用这些方法的唯一原因,请继续阅读...)
我有一个 GenManager class,它使用两个通用类型参数。这是没有实现的 class 定义。 (而且我知道,这仅适用于 entities/tables 使用单个 PK 而不是使用复合键,正如所讨论的 here)
public class GenManager<Entity, EntityKey> where Entity : class, IEFEntity {}
这意味着实体类型参数必须是实现接口 IEFEntity 的 class。因此,在我的应用程序的任何地方,假设一个控制器,我现在可以使用以下方法创建一个实例:
private GenManager<debiteur, int> DebiteurManager;
private GenManager<schakeling, int> SchakelingManager;
但是例如:
private GenManager<anotherClass, int> AnotherClassManager;
将失败,因为 anotherClass
未实现 IEFEntity。但是回到 GenManager class。这是没有所有实现的第一个概述
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
class 的第一个泛型类型 Entity
必须是实现 IEFEntity
的 class,泛型类型 [=] 也必须如此31=] 在方法中使用。所以在我的控制器中,例如我现在可以使用这个语句:
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 语句无法对 'object' 类型的变量进行操作,因为 'object' 会不包含 'GetEnumerator' 的 public 定义。此外,使用智能感知仅显示 4 个标准方法 Equals(object obj)、GetHashCode()、GetType() 和 ToString()。参见 image
所以我尝试使用 as List<FKEntity>
成功转换它并将结果分配给 FKEntityListWithCast
现在我使用 foreach 没有收到任何错误消息。
所以我想,非常好,我只是使用这个 return 语句并且它有效:
return FKEntityListWithCast.Any(item => item.GetPKValue().ToString() == fk.ToString());
上面的 return 语句没有给出错误并且所有内容都可以编译,但问题是在运行时 FKEntityListWithCast
没有得到值。它保持为 NULL。所以问题是:
在运行时获取值但无法循环:
var FKEntityList = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry);
在运行时获取无值(NULL)但可以循环通过:
var FKEntityListWithCast = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry) as List<FKEntity>;
如有任何帮助,我们将不胜感激!
ICollection<FKEntity> FKEntityList = typeof(Entity).GetProperty(typeof(FKEntity).Name).GetValue(dbEntry) as ICollection<FKEntity>;
仍然是一个无赖,没有人能回答这个问题