将 List 转换为 typeof UnderlyingSystemType

Convert List to typeof UnderlyingSystemType

我目前正在处理使用 dynamic-linq 的代码,我 运行 在使用 List<BaseClass> 时遇到问题,其中列表实际上包含 [=17] 的列表=] Class.

当我执行下面的代码时,我得到一个 ParseException:

var list = new List<BaseClass>();

list.Add(new Person
{
  FirstName = "Joe",
  Surname   = "Bloggs"
});

list.Where("FirstName == @0", "Joe");

例外情况:

请看下面BaseClass

public class BaseClass 
{
    public int Id { get; set; }
}

Person class:

public class Person : BaseClass
{
   public string FirstName { get; set; }
   public string Surname   { get; set; }
}

我可以通过执行以下代码克服错误:

var list = new List<BaseClass>();

list.Add(new Person
{
  FirstName = "Joe",
  Surname   = "Bloggs"
});            

var newList = CreateListOfCorrectType<BaseClass>(list);
newList.Where("FirstName == @0", "Joe");

请参阅下面的CreateListOfCorrectType<T>方法:

private IList CreateListOfCorrectType<T>(
         List<T> list) 
{
  if (list.Count == 0)
  {
    return list;
  }

  var typeInfo = list.FirstOrDefault().GetType();

  var correctListType   = typeof(List<>).MakeGenericType(typeInfo.UnderlyingSystemType);
  var listOfCorrectType = (Activator.CreateInstance(correctListType)) as IList;

  list.ForEach(x => listOfCorrectType.Add(x));

  return listOfCorrectType;
}

我的 问题 是使用 CreateListOfCorrectType 是否是解决问题的最佳方法?如果不是,我有什么选择可以让 List<BaseClass> 成为正确的类型。

我希望将其与现有代码一起使用,并且无法更改现有的 List<> 类型。并且 CreateListOfCorrectType 方法不知道 Person class.

请注意 class 名称和变量仅用于说明目的。

更新

下面乐观主义者的回答让我找到了问题的解决方案,请参阅下面使用的扩展方法:

public static IList ToDerivedListType(this IList list)
    {
        if (list == null || list.Count == 0) 
        {
            return list;
        }

        var type       = list.Cast<object>().FirstOrDefault().GetType();
        var castedList = typeof(Enumerable).GetMethod("Cast", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
                                           .MakeGenericMethod(type)
                                           .Invoke(null, new[] { list });

        return typeof(Enumerable).GetMethod("ToList", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
                                 .MakeGenericMethod(type)
                                 .Invoke(null, new[] { castedList }) as IList;           
    }

System.Linq.Enumerable.CastMakeGenericMethod 是关键。

如何使用 OfType linq 方法:

list.OfType<Person>().Where("FirstName == @0", "Joe");

https://msdn.microsoft.com/en-us/library/vstudio/bb360913(v=vs.100).aspx

根据实际用例,有些地方可以改进:

  • 运行时开销:CreateListOfCorrectType 函数将所有元素复制到一个新集合中,这会导致不必要的开销,以防仅从返回的集合中取出一个子集。
  • 映射函数的适用范围:可以扩大到 IEnumerable
  • 最后,映射和过滤功能可以合二为一,减少消费函数的代码量。

System.Linq.Enumerable.CastMakeGenericMethod 可以用来实现:

static public class Extension
{
    static public IEnumerable CastDynamic(this  IEnumerable Source, Type Type)
    {
        return
            (IEnumerable)
            typeof(Enumerable)
            .GetMethod("Cast", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
            .MakeGenericMethod(Type)
            .Invoke(null, new[] { Source });
    }

    static public IEnumerable CastToFirstType(this  IEnumerable Source)
    {
        if (0 == Source.Take(1).Count())
        {
            return Source;
        }

        return CastDynamic(Source, Source.Cast<object>().FirstOrDefault().GetType());
    }

    static public IEnumerable WhereCastToFirstType(this IEnumerable Source, string Predicate, params object[] values)
    {
        return Source.CastToFirstType().Where(Predicate, values);
    }
}

如果试图模仿您在抛出异常方面展示的功能。存在差异,因为转换是在映射函数 returns.

之后完成的