在泛型方法中仅设置第二个参数类型

时间:2015-06-18 06:36:26

标签: c# .net generics clr

我必须创建一个方法,用于从具有指定类型的集合中选择firts属性。

我已经创建了这样的方法(为简洁起见,我删除了一些部分):

public static IQueryable<TResult> SelectFirstPropertyWithType<T, TResult>(this IQueryable<T> source)
{
    // Get the first property which has the TResult type
    var propertyName = typeof(T).GetProperties()
        .Where(x => x.PropertyType == typeof(TResult))
        .Select(x => x.Name)
        .FirstOrDefault();

    var parameter = Expression.Parameter(typeof(T));
    var body = Expression.Convert(Expression.PropertyOrField(parameter, propertyName), typeof(TResult));
    var expression = Expression.Lambda<Func<T, TResult>>(body, parameter);

    return source.Select(expression);
}

我可以将此方法称为:

List<Person> personList = new List<Person>();

// .. initialize personList

personList.AsQueryable()
          .SelectFirstPropertyWithType<Person, int>()
          .ToList();

一切正常。

但是,我不想将第一个参数类型设置为Person,因为编译器可以从集合的源中推断出这个参数类型。有没有办法像这样调用这个方法:

.SelectFirstPropertyWithType<int>()

问题是我的方法中需要T参数,我不想在运行时使用反射创建Func

感谢。

2 个答案:

答案 0 :(得分:3)

没有。编译器应该能够推断所有类型参数。如果它不能要求你指定所有这些。

编译器无法告诉您它可以推断出第一个或第二个,因此它不会有非确定性的编译应用程序,而是会中断。

答案 1 :(得分:2)

C#Generics根本不允许您指定类型参数的子集。这是全有或全无。

解决这个问题的方法是编写一个流畅的界面。您将此操作分解为一系列方法。

 public class FirstPropertyWithTypeSelector<T>
 {
     private readonly IQueryable<T> _source;

     public FirstPropertyWithTypeSelector(IQueryable<T> source)
     {
        _source = source;
     }

     public IQueryable<TResult> OfType<TResult>() 
     {
         // Get the first property which has the TResult type
          var propertyName = typeof(T).GetProperties()
             .Where(x => x.PropertyType == typeof(TResult))
             .Select(x => x.Name)
             .FirstOrDefault();
         var parameter = Expression.Parameter(typeof(T));
         var body = Expression.Convert(Expression.PropertyOrField(parameter, propertyName), typeof(TResult));
          var expression = Expression.Lambda<Func<T, TResult>>(body, parameter);
         return _source.Select(expression);
     }
 }

 public static FirstPropertyWithTypeSelector<T> SelectFirstProperty(this IQueryable<T> source)
 {
    return new FirstPropertyWithTypeSelector<T>(source);
 }

现在你可以致电:

  personList.AsQueryable()
      .SelectFirstProperty().OfType<int>()
      .ToList();