【问题标题】:Why is there not a `fieldof` or `methodof` operator in C#? [closed]为什么 C# 中没有 `fieldof` 或 `methodof` 运算符? [关闭]
【发布时间】:2009-07-31 17:33:41
【问题描述】:

它们可以按如下方式使用:

FieldInfo field = fieldof(string.Empty);
MethodInfo method1 = methodof(int.ToString);
MethodInfo method2 = methodof(int.ToString(IFormatProvider));

fieldof 可以编译为 IL:

ldtoken <field>
call FieldInfo.GetFieldFromHandle

methodof 可以编译为 IL 为:

ldtoken <method>
call MethodBase.GetMethodFromHandle

无论何时使用typeof 运算符,您都会获得完美的“查找所有引用”结果。不幸的是,一旦你进入领域或方法,你最终会遇到令人讨厌的黑客攻击。我认为您可以执行以下操作...或者您可以返回按名称获取字段。

public static FieldInfo fieldof<T>(Expression<Func<T>> expression)
{
    MemberExpression body = (MemberExpression)expression.Body;
    return (FieldInfo)body.Member;
}

public static MethodInfo methodof<T>(Expression<Func<T>> expression)
{
    MethodCallExpression body = (MethodCallExpression)expression.Body;
    return body.Method;
}

public static MethodInfo methodof(Expression<Action> expression)
{
    MethodCallExpression body = (MethodCallExpression)expression.Body;
    return body.Method;
}

public static void Test()
{
    FieldInfo field = fieldof(() => string.Empty);
    MethodInfo method1 = methodof(() => default(string).ToString());
    MethodInfo method2 = methodof(() => default(string).ToString(default(IFormatProvider)));
    MethodInfo method3 = methodof(() => default(List<int>).Add(default(int)));
}

【问题讨论】:

  • 你能想象这个功能一年会被使用多少次吗?
  • 我正在用 C# 编写 CLI 实现 - 这对于在 JIT 中识别 IL 中的特殊引用非常有帮助,因此我可以区别对待它们。例如,我想用ldc.i4 &lt;int32 offset&gt; 内联替换call RuntimeHelpers.get_OffsetToStringData 的任何IL 实例(在本机代码生成之前)。
  • 这是一个经常被请求的功能,因此显然有相当常见的用例。也就是说,显然不会实现自动道具或 where 子句的普及。
  • 对于任何处理 WPF(想想依赖属性)的人来说,这将是一个非常有用的功能,更一般地说,对于任何实现 INotifyPropertyChanged 的人来说。
  • 即使不使用 WPF 的人仍然会抛出ArgumentException

标签: c# reflection


【解决方案1】:

您实际上可以避免同时使用反射和 lambda (.NET Framework 2.0)。考虑以下类:

public class methodof<T>
{
    private MethodInfo method;

    public methodof(T func)
    {
        Delegate del = (Delegate)(object)func;
        this.method = del.Method;
    }

    public static implicit operator methodof<T>(T methodof)
    {
        return new methodof<T>(methodof);
    }

    public static implicit operator MethodInfo(methodof<T> methodof)
    {
        return methodof.method;
    }
}

它的用法:

MethodInfo writeln = (methodof<Action>)Console.WriteLine;
MethodInfo parse = (methodof<Func<string, int>>)int.Parse;

【讨论】:

  • +1 对于一个非常优雅的解决方案,加上用于重载强制转换运算符的样式点,使其看起来更加内置。现在,如果只有 C# 允许我们在属性上显式引用 get/set 访问器,那么这也适用于那些。
  • 很遗憾不起作用
  • @hazzik 它对我有用。请指明错误。
  • 我同意这很好,但不幸的是,这需要您明确指定方法签名,因此它与完全内置的 MethodInfo parse = ((Func&lt;string, int&gt;)int.Parse).Method; 基本相同,因此不需要任何帮助程序类。在我看来,这里的重点是避免这种强制转换,这将使您能够在运行时实际 获取 签名,而您需要在编译时提供的只是方法名称标记。
  • 我对@9​​87654324@(未返回)方法有疑问。
【解决方案2】:

Eric Lippert(在 C# 设计团队中)对此主题进行了出色的概述/讨论 here。引用:

这是一个很棒的功能,几乎参与设计过程的每个人都希望我们能做到,但我们选择不这样做有很好的实际原因。如果有一天设计和实施它是我们可以花费有限预算的最佳方式,我们会这样做。在此之前,请使用反射。

【讨论】:

  • 'Foof' 会是一个更合适的咒骂 :)
  • 我在我的问题下添加了一条评论,其中包含一个非常有用的用例。当然可以使用它——如果我可以编写 C# 代码来充分利用 ldtoken IL 指令,那将非常有帮助。或者 cpblkinitblk
  • 我知道,我将实现 hack,然后将这些辅助方法添加到我在 JIT 之前以特殊方式处理的调用列表中!唯一的缺点是它会导致 JIT 时间性能损失小、语法笨拙和程序集稍大。
【解决方案3】:

@280Z28 - 当我找到您的问题和代码时,我们只是坐下来想办法做到这一点。我们需要一个 PropertyOf 方法,所以我添加了它。这是以防其他人需要它。谢谢你的好问题。

     public static PropertyInfo PropertyOf<T>(Expression<Func<T>> expression)
    {
        MemberExpression body = (MemberExpression)expression.Body;
        PropertyInfo pi = body.Member as PropertyInfo;
        if (pi != null)
        {
            return pi;
        }
        else throw new ArgumentException("Lambda must be a Property.");
    } 

      [TestMethod()]
    public void MethodofPropertyOfTest<T>()
    {

        string foo = "Jamming";
        MethodInfo method1 = ReflectionHelper.Methodof(() => default(string).ToString());
        PropertyInfo prop = ReflectionHelper.PropertyOf(() => default(string).Length);
        Assert.AreEqual(method1.Invoke(foo, null), "Jamming");
        Assert.AreEqual(prop.GetGetMethod().Invoke(foo, null), foo.Length);
    }

【讨论】:

  • 做得很好。我在这里做了类似的事情:stackoverflow.com/questions/269578/… 但我喜欢你的作为一个可靠的通用解决方案:
  • 如果您在生产代码中需要这种类型的操作,请注意 - 对给定输入的 methodof、fieldof 或 propertyof 调用返回的值是常量。每当我在一个类中需要它们时,我要么有一个静态只读字段,我将其初始化为 FieldInfo/MethodInfo/PropertyInfo,要么我使用适当的 Dictionary&lt;Type,MemberInfo&gt; 映射。如果您查看由表达式树糖生成的 IL,您会发现您不想运行它,除非您必须这样做。我认为让它们作为语言运算符的第一大优势是 IL 可以/将非常简洁。
  • 转角案例:stackoverflow.com/questions/6658669/…。我认为这不是这种工作的正确方法。此外,我认为最好检查一元表达式,例如 &lt;object&gt; () =&gt; IntProperty() 等盒装转换。
【解决方案4】:

这是一个泛型版本,可以使用F2重命名,无需修改已有代码 在示例中,方法名称为 GetPKValue

var typFactory = typeof(FormFieldFactory<>).MakeGenericType(entity.GetType());
var methodName = new Func<object, object>(FormFieldFactory<object>.GetPKValue).Method.Name;

var theMethod =
    (Func<object, object>)Delegate.CreateDelegate(
        typeof(Func<object, object>)
        , typFactory.GetMethod(methodName)
    );

【讨论】:

    猜你喜欢
    • 2013-01-15
    • 2011-09-14
    • 1970-01-01
    • 2016-06-30
    • 2010-10-24
    • 2011-10-04
    • 2014-03-22
    • 2020-06-19
    相关资源
    最近更新 更多