表现动态与反思

时间:2017-12-07 10:04:29

标签: c# performance linq dynamic reflection

我有以下可能性来检索列表中的值:

使用反射:

foreach (var item in items) {
  var property=item.Fields[fieldName].GetType().GetProperty("Id");
  var value=property.GetValue(item.Fields[fieldName]);
  if (value==searchValue) {
      filtered.Add(item);
   }
}

使用动态:

foreach (var item in items) {
   dynamic itemProperty=item.Fields[fieldName];
   if (itemProperty.Id==searchValue) {   
      filtered.Add(item);
   }
}

两个循环都是一样的。它们按字段[fieldName]过滤IEnumerable(或List),字段[fieldName]可以是不同类型,但都包含一个名为" Id"的int属性。

我想知道哪一个会有更好的表现。 另外:将其中一个更改为LinQ-Query会增加性能吗?

1 个答案:

答案 0 :(得分:5)

执行此操作的最简单方法IMO是定义一个具有int Id {get;}属性的接口,并让您的类型实现它。然后编码到界面。如果您的现有代码是通用的,您甚至可以添加where T : IYourInterface约束,但您可以以任一方式转换为IYourInterface(假设T实际上实现了接口)。

如果接口不是选项:

反思和dynamic都有开销; dynamic有更好的优化(重新使用缓存策略)。

如果您的items列表是针对特定T的强列表(此处T未知),那么您可以可能进一步优化此概念用于编译委托的LINQ表达式:

static class IdFetcher
{
    public static int Fetch<T>(T item) => IdFetcher<T>.Fetch(item);
}
static class IdFetcher<T>
{
    public static int Fetch(T item) => fetch(item);
    static readonly Func<T, int> fetch;
    static IdFetcher()
    {
        var p = Expression.Parameter(typeof(T), "item");
        fetch = Expression.Lambda<Func<T, int>>(
            Expression.PropertyOrField(p, "Id"), p).Compile();
    }
}

然后只使用IdFetcher<T>.Fetch(obj)IdFetcher.Fetch(obj)(第一个更直接;第二个对于无法指定T的匿名类型非常有用)

除此之外:如果你想知道哪个更快:为它们计时(对于大量的迭代)。