【问题标题】:Efficient way to access a property of a class by the string name通过字符串名称访问类属性的有效方法
【发布时间】:2016-01-31 08:37:25
【问题描述】:

我想通过名称访问属性值。我知道它的唯一方法是使用这样的代码进行反射:

 public static object GetPropValue(object src, string propName)
 {
     return src.GetType().GetProperty(propName).GetValue(src, null);
 }

还有其他方法吗(使用例如 codegen 等)?

【问题讨论】:

  • 代码生成并构建一个表达式树,然后将其编译成一个函数。
  • 如果您需要保留 object 类型的参数和 object 类型的结果,请按照 Jon 所说的方式使用 codegen。但是,如果您可以使用强类型函数,那么为属性 getter 创建一个委托既可以简化代码,又可以在运行时更快(因为它避免了中间步骤)。
  • 当然,我说的是对象类型。你能告诉我(作为答案)使用这种方法的一些实现吗?

标签: c# reflection codegen


【解决方案1】:

我知道它的唯一方法是使用这样的代码进行反射:

反射是一种方式,它也很昂贵(所以我听说过),所以你创建一个缓存来加速多个属性查找(这就是 所做的)。类似的东西(完全示例代码):

private static Dictionary<PropertyInfoKey, PropertyInfo> propertyCache = 
  new Dictionary<PropertyInfoKey, PropertyInfo>()

private class PropertyInfoKey : IEquatable 
{
  public PropertyInfoKey(string fullName, string propertyName)
  {  
    FullName = fullName;
    PropertyName = propertyName
  }

  public string FullName { get; private set; }
  public string PropertyName { get; private set; }

  public bool Equals(PropertyInfoKey other)
  {
    if ( ..// do argument checking

    var result = FullName == other.FullName
      && PropertyName == other.PropertyName;

    return result;
  }
}

public static bool TryGetPropValue<T>(T src, 
  string propName, 
  out object value)
  where T : class
{
  var key = new PropertyInfoKey(
    fullName: typeof(T).FullName,
    propertyName: propName
  );

  PropertyInfo propertyInfo;
  value = null;
  var result = propertyCache.TryGetValue(key, out propertyInfo);

  if (!result)
  {
    propertyInfo = typeof(T).GetProperty(propName);

    result = (propertyInfo != null);

    if (result)
    {
      propertyCache.Add(key, propertyInfo)
    }  
  }

  if (result)
  {
    value = propertyInfo.GetValue(src, null);
  }
  return result;
}

(*也许您可以改用HashSet,因为PropertyInfoKey 在技术上也可以保存PropertyInfo,并且它正在实现IEquatable

或者....

如果您这样做是因为您有很多类具有相似的属性但完全不同且不相关......

public interface IName
{
  public string Name { get; }
}

public class Car : IName
{
  public string Name { get; set; }
  public string Manufacturer { get; set; }
}

public class Animal : IName
{
  public string Name { get; set; }
  public string Species { get; set; }
}

public class Planet : IName
{
  public string Name { get; set; }
  public string ContainSystem { get; set; }
}

那你就可以了

public static string GetName(this IName instance)
{
  return instance.Name;
}

【讨论】:

  • 非常优雅的实现,使用缓存而不是完全反射来节省资源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
  • 2015-07-11
  • 2022-07-22
相关资源
最近更新 更多