【问题标题】:return generic IEnumerable when passing concrete type parameter for a generic method为泛型方法传递具体类型参数时返回泛型 IEnumerable
【发布时间】:2013-07-17 13:53:46
【问题描述】:

此代码示例取自此答案https://stackoverflow.com/a/16491759/98706

public static Boolean PurgeDataObject(this IDataObject dataObject, Guid uid)
{
    return PurgeDataObjectImpl((dynamic) dataObject, uid);
}

private static Boolean PurgeDataObjectImpl<T>(T dataObject, Guid uid)
    where T : IDataObject
{
    return DataProvider.DeleteDataObject<T>(uid, DataProvider.GetConnection());
}

我有类似的情况,我想在执行时根据类型返回相关的 EF 实体,以尝试清理一些现有的继承代码,如下所示:(

不同之处在于我希望函数返回一个IEnumerable&lt;T&gt;

GetFilteredData 没有T 的概念,所以我得到The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?) 的编译错误

    private IEnumerable<T> GetFilteredData(Type entityType, SortedList<string, string> filterList, List<int> weeks)
    {
        return GetFilteredDataImpl((dynamic)entityType, filterList, weeks);
    }

    private IEnumerable<T> GetFilteredDataImpl<T>(T entityType, SortedList<string, string> filterList, List<int> weeks) where T : EntityObject
    {
        var data = _modelContext.CreateObjectSet<T>().AsExpandable();
          // do more filtering and then call .ToList() to return a List<T>
    }

【问题讨论】:

  • 好吧,在GetFilteredData 中,编译器应该如何知道 T 是什么?它不受约束,也没有定义为参数。
  • @LightStriker 是的,我在我的问题中发表了评论说The GetFilteredData won't have a concept of T so I get the compile error 我想我现在正在寻找一种替代方法。
  • 您认为使用 GetFilteredData 的代码会是什么样子?

标签: c# .net generics dynamic types


【解决方案1】:

您不能在不使用反射的情况下将Type 类转换为通用T 参数。该参数也需要作为方法的一部分出现。

Jon Skeet 通过示例结合泛型使用类型推断,以保证类型安全并简化泛型代码。不幸的是,您将失去使用 Type 和反射的类型安全性。

private IEnumerable<EntityObject> GetFilteredData(Type entityType,
                                                  SortedList<string, string> filterList,
                                                  List<int> weeks)
{
    var method = typeof(<class>).GetMethod("GetFilteredDataImpl");
    var generic = method.MakeGenericMethod(entityType);
    return (IEnumerable<EntityObject>)generic.Invoke(this, new[] { filterList, weeks });
}

private IEnumerable<T> GetFilteredDataImpl<T>(SortedList<string, string> filterList,
                                              List<int> weeks)
    where T : EntityObject
{
    var data = _modelContext.CreateObjectSet<T>().AsExpandable();
      // do more filtering and then call .ToList() to return a List<T>
}

但是,您可以创建一个对象来传递。

private IEnumerable<EntityObject> GetFilteredData(Type entityType, SortedList<string, string> filterList, List<int> weeks)
{
    var instance = (EntityObject)Activator.CreateInstance(entityType);
    return GetFilteredDataImpl((dynamic)instance, filterList, weeks);
}

private IEnumerable<T> GetFilteredDataImpl<T>(T entityType, SortedList<string, string> filterList, List<int> weeks) where T : EntityObject
{
    var data = _modelContext.CreateObjectSet<T>().AsExpandable();
      // do more filtering and then call .ToList() to return a List<T>
}

这仍然会返回一个IEnumerable&lt;EntityObject&gt;,但它会产生垃圾,并且您正在用一个ArgumentException 换一个InvalidCastException

【讨论】:

  • 如果我将GetFilteredData 的返回类型更改为IEnumerable&lt;EntityObject&gt;,那么我现有的代码可以正常工作,因为GetFilteredDataImpl 和使用dynamic.. 我不需要进一步思考变化。但是我的问题是我必须在其他函数中对返回的结果进行大量转换,这样我才能设置正确的属性,这是我试图避免的:(
  • 您遇到的问题是使用非泛型方法来获得泛型结果。你会丢失从泛型到非泛型的类型信息。
  • 感谢您的建议,我肯定需要重新考虑它以使其适合当前代码。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-24
  • 2013-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多