C# 调用泛型方法时,将PropertyInfo用作泛型类型
背景 我正在使用EF,我有很多表。当我插入一个包含导航属性内容但没有id的新实体(我从xls文件中读取内容)时,我不想显式加载所有导航属性。这是太多的代码。所以我尝试了一种通用的方法:C# 调用泛型方法时,将PropertyInfo用作泛型类型,c#,entity-framework,generics,reflection,system.reflection,C#,Entity Framework,Generics,Reflection,System.reflection,背景 我正在使用EF,我有很多表。当我插入一个包含导航属性内容但没有id的新实体(我从xls文件中读取内容)时,我不想显式加载所有导航属性。这是太多的代码。所以我尝试了一种通用的方法: private void loadExistingNavigationProperties<TEntity>(TEntity entityToInsert) where TEntity : class { Type type = typeof(TEntity); var propert
private void loadExistingNavigationProperties<TEntity>(TEntity entityToInsert) where TEntity : class
{
Type type = typeof(TEntity);
var properties = type.GetProperties().Except(type.GetProperties().Where(x => x.Name.Contains("id")));
foreach (PropertyInfo property in properties)
{
if (property.PropertyType.FullName.Contains("MyNamespace"))
{
property.SetValue(entityToInsert, findNavigationProperty<???>(property.GetValue(entityToInsert)));
}
}
}
传递导航属性的当前值。它包含所有信息,如名称或其他信息,但不包含id。首先,我将获取所有具有该类型的可用导航属性。然后我搜索是否有一个属性与当前属性具有相同的属性。然后返回该属性并将其设置为导航属性
编辑:
public List GetAllEntries(),其中tenty:class
{
使用(var dbContext=newinventardbenties(MainWindow.connectionName))
{
返回GetAllEntries(dbContext);
}
}
公共列表GetAllEntries(InventardBenties dbContext),其中tenty:class
{
返回dbContext.Set().ToList();
}
问题
我现在的问题是如何告诉方法
findNavigationProperty
泛型类型就是属性值所具有的类型。因此,将?
替换为类型。您可以检索这样的泛型类型:
var item = propertyInfo.GetGenericArguments()[0];
您可以使用“is”检查它是否为类型
您还可以执行以下操作:
item.BaseType == typeof(Whatever type your navigation props inherit);
正如我在评论中已经提到的:
泛型类型参数在编译时解析
因此,您无法从
System.type
检索泛型类型问题的关键是使用
System.Type
而不是泛型。请注意,我没有测试下面的代码,因为我还没有将EF.
安装到我的知识DbContext的
系统中。Type
重载应该可以正常工作
private void loadExistingNavigationProperties(TEntity entityToInsert),其中TEntity:class
{
类型tenty=类型of(tenty);
var properties=tenty.GetProperties()。除了(tenty.GetProperties()。其中(x=>x.Name.Contains(“id”));
foreach(属性中的PropertyInfo属性)
{
if(property.PropertyType.FullName.Contains(“MyNamespace”))
{
object val=findNavigationProperty(property.GetValue(entityToInsert),tenty);
SetValue(entityToInsert,val);
}
}
}
私有对象findNavigationProperty(对象navigationPropertyValue,类型tEntity)
{
DbSet navigationProperties=GetAllEntries(tEntity);
foreach(navigationProperties中的var实体)
{
//您可能会遇到类型问题。
//如果是:转换为正确的类型或更改“PropertiesReequal”。
if(属性相等(实体、导航属性值))
{
返回实体;
}
}
返回navigationPropertyValue;
}
公共数据库集GetAllEntries(tEntity类型)
{
使用(var dbContext=newinventardbenties(MainWindow.connectionName))
{
返回GetAllEntries(dbContext,tEntity);
}
}
公共数据库集GetAllEntries(InventardBenties数据库上下文,类型tEntity)
{
返回dbContext.Set(tenty);
}
您无法在运行时检索泛型类型。泛型类型必须在编译时可解析。如果要将运行时解析的类型传递给方法,必须通过传递反射的System.type
来实现。GetAllEntries()
是否有接受System.Type
参数的重载?@NoelWidmer我添加了GetAllEntries方法。它不接受System.TYPE参数。您是否还有InventardBenties
的来源?我想它是.NET类型的。在这种情况下,您能告诉我它派生的类名的名称吗。(我想看看是否存在接受System.Type
而不是泛型参数的inventardbenties.Set()
重载)泛型和反射不能很好地混合。泛型是编译时构造,而反射是运行时构造。但您可以。@NoelWidmer:InventardBenties源于DbContext。是的,它可以工作。而且它比通过反射调用方法要干净得多。非常感谢。我只是不明白为什么DbSet的方法比DbSet少,但这是另一个问题,强制转换也解决了这个问题。@L3n95酷!我没有经常使用DbSet,因此无法回答这个问题。我总是喜欢泛型类型而不是一般对象类型。但是在使用反射类型的情况下,通常没有更好的选择。
var item = propertyInfo.GetGenericArguments()[0];
item.BaseType == typeof(Whatever type your navigation props inherit);
private void loadExistingNavigationProperties<TEntity>(TEntity entityToInsert) where TEntity : class
{
Type tEntity = typeof(TEntity);
var properties = tEntity.GetProperties().Except(tEntity.GetProperties().Where(x => x.Name.Contains("id")));
foreach (PropertyInfo property in properties)
{
if (property.PropertyType.FullName.Contains("MyNamespace"))
{
object val = findNavigationProperty(property.GetValue(entityToInsert), tEntity);
property.SetValue(entityToInsert, val);
}
}
}
private object findNavigationProperty(object navigationPropertyValue, Type tEntity)
{
DbSet navigationProperties = GetAllEntries(tEntity);
foreach (var entity in navigationProperties)
{
// You may get a type issue.
// If so: cast to the correct type or change "propertiesAreEqual".
if (propertiesAreEqual(entity, navigationPropertyValue))
{
return entity;
}
}
return navigationPropertyValue;
}
public DbSet GetAllEntries(Type tEntity)
{
using (var dbContext = new InventarDBEntities(MainWindow.connectionName))
{
return GetAllEntries(dbContext, tEntity);
}
}
public DbSet GetAllEntries(InventarDBEntities dbContext, Type tEntity)
{
return dbContext.Set(tEntity);
}