4

有人知道这是否可能吗?我有一个自定义 Attribute 类,它定义了一个为属性实现 IComparer 的 Type。我想通过反射访问该类型并将其实例化以在 IEnumerable.OrderBy() 中使用:

[System.AttributeUsage(System.AttributeTargets.Property)]
public class SortComparer : System.Attribute
{
    public Type ComparerType;

    public SortComparer(Type ComparerType)
    {
        this.ComparerType = ComparerType;
    }
}


var property = typeof(PerTurbineResultViewModel).GetProperty(SortColumn);

var sortComparer = property.GetCustomAttributes(typeof(SortComparer), true).FirstOrDefault() as SortComparer;




if (sortComparer != null)
{
    var insta = Activator.CreateInstance(sortComparer.ComparerType);
    this.Results = lstResults.Select(r => new ResultViewModel(r)).
                        OrderBy(p => property.GetValue(p, null), insta));
}

上面的代码不能编译,因为OrderBy<TSource, TResult>要求第二个参数是类型IComparer<TResult>(在编译时是未知的)。

有没有办法实例化“insta”变量并将其转换为IComparer<TResult>使用“属性”中的类型信息?

编辑:第一个选项让我非常接近:

Func<ResultViewModel, PropertyInfo> sel = t => property;

this.Results = infoGeneric.Invoke(Results, new object[] { vals, sel, insta }) as IEnumerable<ResultViewModel>;

除了我得到属性选择器的运行时异常:

// Object of type 'System.Func`2[ResultViewModel,System.Reflection.PropertyInfo]' cannot be converted to type 'System.Func`2[ResultViewModel,System.Reflection.RuntimePropertyInfo]'.

RuntimePropertyInfo 似乎是内部的......还有其他方法可以传入属性选择器吗?

4

2 回答 2

3

基本上你有两个选择:

  • 也可以使用反射调用OrderBy:获取泛型方法定义,然后调用MethodInfo.MakeGenericMethod以获取构造的版本,然后调用它。
  • 在 C# 4 中使用dynamic来让内置的迷你编译器为您完成繁重的工作

编辑:因为property.GetValue()只有返回object,你几乎肯定必须通过反射路线。要么,要么你可以使用第三种,一个可怕但非常简单的选择......

...让你所有的比较器实现IComparer<object>,并在其中进行转换。然后你TResult会是object,你可以投:

object tmp = Activator.CreateInstance(sortComparer.ComparerType);
IComparer<object> comparer = (IComparer<object>) tmp;
this.Results = lstResults.Select(r => new ResultViewModel(r))
                         .OrderBy(p => property.GetValue(p, null), comparer);
于 2012-08-13T21:11:52.317 回答
0

有时通过工厂函数实例化帮助类来使用函数式方法会更好。

  • 实现IComparer接口的泛型类 [ 1 ]

    internal class GenericEqualityComparer<T> : IEqualityComparer<T>
    {
      private readonly Func<T, T, bool> _comparer;
    
      public GenericEqualityComparer(Func<T, T, bool> comparer) {
          _comparer = comparer;
      }
    
      public bool Equals(T x, T y)
      {
          return _comparer(x, y);
      }
    
      public int GetHashCode(T obj)
      {
          return base.GetHashCode();
      }
    }
    
  • 使用工厂方法实例化通用比较器类 [ 2 ] 并将Func<T, T, int> compare委托作为参数传递给此类

      IComparer<Point> comparer = comparator<Point>((a, b) =>
      {
          return (a.X + a.Y) - (b.X + b.Y);
      });
    
      comparer.Compare(new Point(0, 0), new Point(0, 0)); // should return zero
      comparer.Compare(new Point(100, 0), new Point(0, 0)); // should return a value greater than zero
      comparer.Compare(new Point(0, 0), new Point(100, 0)); // should return a value less than zero
    
于 2019-05-17T15:27:37.633 回答