【问题标题】:Use PropertyInfo as generic type when calling a generic method调用泛型方法时使用 PropertyInfo 作为泛型类型
【发布时间】:2017-05-05 09:33:13
【问题描述】:

背景

我正在使用 EF,我有很多表。当我插入具有导航属性内容但没有 id 的新实体时(我正在从 xls 文件中读取内容),我不想显式加载所有导航属性。这是太多的代码。所以我尝试了一种通用的方式:

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

我有我的entityToInsert。如果它具有导航属性 (contains("MyNamespace")),我会检查它的所有属性。如果这是真的,导航属性应该被加载(见下文)并设置。

private object findNavigationProperty<TNavigationProperty>(TNavigationProperty navigationPropertyValue) where TNavigationProperty : class
{
    List<TNavigationProperty> navigationProperties = GetAllEntries<TNavigationProperty>();
    foreach (var entity in navigationProperties)
    {
        if (propertiesAreEqual(entity, navigationPropertyValue))
        {
            return entity;
        }
    }
    return navigationPropertyValue;
}

传递了导航属性属性的当前值。它包含所有信息,例如名称或其他信息,但不包含 id。首先,我得到所有具有该类型的可用导航属性。然后我正在搜索是否有一个属性与当前属性相同。然后这个返回并设置为导航属性。

编辑:

public List<TEntity> GetAllEntries<TEntity>() where TEntity : class
{
    using (var dbContext = new InventarDBEntities(MainWindow.connectionName))
    {
        return GetAllEntries<TEntity>(dbContext);
    }
}

public List<TEntity> GetAllEntries<TEntity>(InventarDBEntities dbContext) where TEntity : class
{
    return dbContext.Set<TEntity>().ToList();
}

问题

我现在的问题是如何告诉方法findNavigationProperty 泛型类型是属性值所具有的类型。所以用类型替换???。

【问题讨论】:

  • 您无法在运行时检索泛型类型。泛型类型在编译时必须是可解析的。如果要将运行时解析的类型传递给方法,则必须通过传递反射的System.Type 来实现。 GetAllEntries() 是否有接受System.Type 参数的重载?
  • @NoelWidmer 我添加了 GetAllEntries 方法。它不接受 System.Type 的参数
  • 你也有InventarDBEntities的来源吗?我想它是一种 .NET 类型。在那种情况下,你能告诉我它派生的类名的名称吗? (我想看看是否存在接受 System.Type 而不是泛型参数的 InventarDBEntities.Set() 重载)
  • 泛型和反射不能很好地混合。泛型是一个编译时结构,而反射是一个运行时结构。不过,您可以 construct a generic method call at runtime。
  • @NoelWidmer:InventarDBEntities 派生自 DbContext。

标签: c# entity-framework generics reflection system.reflection


【解决方案1】:

正如我在评论中已经提到的:
泛型类型参数在编译时解析。
因此,您无法从System.Type 中检索泛型类型。

您的问题的关键是使用 System.Type 而不是泛型。
请注意,我没有测试下面的代码,因为我没有安装 EF。
致我的知识 DbContext 的 System.Type 重载应该可以正常工作。

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

【讨论】:

  • 是的,它有效。它比通过反射调用方法要干净得多。谢谢你。我只是不明白为什么 DbSet 的方法比 DbSet 少,但这是另一个问题,强制转换也解决了这个问题。
  • @L3n95 酷!我没有经常使用 DbSet,因此无法回答这个问题。我总是更喜欢通用类型而不是通用对象类型。但是在使用反射类型的情况下,您通常没有更好的选择。
【解决方案2】:

您可以像这样检索泛型类型:

var item = propertyInfo.GetGenericArguments()[0];

你可以使用“is”来检查它是否是类型

你也可以这样做:

item.BaseType == typeof(Whatever type your navigation props inherit);

【讨论】:

    猜你喜欢
    • 2011-08-26
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 2011-05-18
    • 1970-01-01
    • 2021-12-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多