【问题标题】:How to write accessor expression to infer the type?如何编写访问器表达式来推断类型?
【发布时间】:2016-07-23 19:25:40
【问题描述】:

给定以下代码

[Table("Bar")]
public class Foo {
  [Column("BarID")]
  public int Id { get; set; }
}
public static class MyExtensions {
  public static string TableName(this Type type) {
    var attrib = type.GetCustomAttribute<TableAttribute>(false);
    return attrib?.Name ?? type.Name;
  }
  public static string ColumnName<TType, TMember>(this Type t, Expression<Func<TType, TMember>> accessor) {
    var member = accessor.Body as MemberExpression;
    if (member != null) {
      var field = member.Member;
      var attrib = field.GetCustomAttribute<ColumnAttribute>();
      return attrib?.Name ?? field.Name;
    }
    return null;
  }
}

然后我可以编写类似typeof(Foo).TableName(); 的代码来获取表名

对于列名,我可以使用typeof(Foo).ColumnName((Foo f) =&gt; f.Id)

如何获得 ColumnName 扩展方法来推断访问器表达式中的 TType,以便我可以简单地编码为 type(Foo).ColumnName(f =&gt; f.Id)

【问题讨论】:

  • 您的第二种方法不使用t... 它根本不是真正扩展 Type (从某种意义上说,它实际上会从类型对象中调用,但您没有t 使用它的值)。不能直接从类型对象替换泛型类型参数。获得泛型的唯一方法是获取类型并使用反射创建泛型方法定义,但在这种情况下,你会被困在返回对象(我认为)。你总是可以让你的扩展方法扩展你的实体类型直接(this MyEntity t)并将方法限制为where MyEntity : EntityBase
  • @pinkfloydx33 是的,我意识到了这一点。我只是想拥有相同的 api 来获取属性上的 ColumnAttribute 值。如果访问器方法不起作用,那么我可以创建一个可以调用的方法,例如 'typeof(Foo).ColumnName(nameof(Foo.Id))'
  • 您仍然可以使用表达式 API 来获取成员表达式而不是 nameof,问题是从类型对象创建泛型类型参数而不直接指定泛型类型。既然您已经知道 Foo,为什么不将它作为方法调用的一部分提供呢? ColumnName&lt;Foo, string&gt;(f =&gt; f.Id) 并放弃扩展方面,转而使用一个参数的普通静态方法?
  • 虽然我猜在那种情况下你不会知道字符串......你可以将这两种方法与一个辅助扩展结合起来,它使用反射创建一个通用方法,然后调用原始版本。但恐怕你将不得不在 somewhere 指定你的类型......虽然可能有一些解决方案我完全忽略了(毕竟它 is 早上 5 点)

标签: c# .net lambda extension-methods


【解决方案1】:

既然你在方法中连参数Type t都不用,那为什么还要是扩展方法呢?

public static string ColumnName<TType, TMember>(
    Expression<Func<TType, TMember>> accessor) { ... }

用法:

ColumnName((Foo f) => f.Id)

这样类型只指定一次。

【讨论】:

    【解决方案2】:

    我得到了以下结果

    public static class Metadata<TType> {
      public static string TableName() {
        var type = typeof(TType);
        var attrib = type.GetCustomAttribute<TableAttribute>(false);
        return attrib?.Name ?? type.Name;
      }
      public static string ColumnName<TMember>(Expression<Func<TType, TMember>> propertyExpresseion) {
        if (propertyExpresseion.Body.NodeType != ExpressionType.MemberAccess) {
          throw new InvalidOperationException();
        }
    
        var member = propertyExpresseion.Body as MemberExpression;
        var property = member.Member;
        var attrib = property.GetCustomAttribute<ColumnAttribute>(false);
        return attrib?.Name ?? property.Name;
      }
    }
    

    然后我可以将其用作

    Metadata<Audit>.TableName();
    Metadata<Audit>.ColumnName(a => a.Id);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-03
      • 2023-03-20
      • 1970-01-01
      • 2010-11-07
      相关资源
      最近更新 更多