【问题标题】:Why not a memberinfo() reflection function for C# [duplicate]为什么不是 C# 的 memberinfo() 反射函数 [重复]
【发布时间】:2011-05-12 21:22:33
【问题描述】:

sizeof()typeof(),但为什么不是memberinfo() 返回System.Reflection.MemberInfo 的实例,用于帮助反射代码选择的代码部分。

例子:

Program() 
{
       Type t = typeof(Foo);

       Foo foo = new Foo();
       PropertyInfo pi = memberinfo(Foo.Name) as PropertyInfo;
       // or shall it be like this
       // PropertyInfo pi = memberinfo(foo.Name) as PropertyInfo;

       string name = pi.GetValue(foo, null);
}

我试图了解是否有一个根本原因可以在 C# 规范中实现。

我不是在抨击什么,我只是在做一些一厢情愿的想法,所以请善待。

【问题讨论】:

  • 它可能很容易实现。我也想要这样的东西。请注意,方法需要替代语法,因为它们可以重载,因此在这种情况下仅指定名称是不够的。
  • 您可以使用表达式树创建类似的东西;这对属性和字段特别有效。
  • @Bryant 你有例子或链接吗?
  • 这里有一个:stackoverflow.com/questions/671968/… 要更深入地了解从表达式树中提取成员信息,您可以查看 Moq 源代码(它们扩展使用 lambda 表达式来获取成员信息。 )
  • 我一直想知道这个,类似的东西,我的意思是编译时反射!

标签: c# reflection language-design


【解决方案1】:

Eric Lippert 在他的 blog 上广泛讨论了这个问题

直接引用该帖子:

就在我的脑海中,这里有几个{为什么没有这样做的原因}。 (1) 你如何明确指定你想要一个特定显式接口实现的方法信息? (2) 如果重载决议会因为不可访问而跳过特定方法怎么办?获取不可访问方法的方法信息是合法的;元数据总是公开的,即使它描述了私人细节。我们应该让私有元数据变得不可能,从而使特性变得弱,还是应该让这成为可能,让 infoof 使用与 C# 的其余部分略有不同的重载解析算法? (3) 你如何指定你想要索引器设置器、属性获取器或事件处理程序添加器的信息?

【讨论】:

    【解决方案2】:

    有几个项目使这种类型的功能变得困难。主要方法之一是重载方法。

    class Example { 
      public void Method() {}
      public void Method(int p1) {}
    }
    

    下面会返回哪个MethodInfo

    var info = memberinfo(Example.Method);
    

    正如 Wesley 所指出的,Eric's Blog 对此问题进行了全面讨论。

    【讨论】:

    • 你的例子有点不对劲,因为Type.GetMethod() 在这种情况下也不起作用......它会抛出一个AmbiguousMatchException。虽然实现infoof 存在语法挑战,但它肯定会使反射敏感代码更易于维护。与 C# 语言的所有其他可能改进相比,infoof 是否足够有价值完全是另一个问题。
    • 它可以返回一个包含所有重载的数组。
    • @LBushkin 不知道这如何使我的示例失效。它指出了使用假设特征 memberinfo 消除重载方法歧义的困难。
    • @jalexiou 按什么顺序排列?
    • @JaredPar 按照与.GetMethods() 相同的顺序返回。
    【解决方案3】:

    编译时成员反射尚未在 C# 中实现的原因有很多 - 但其中大多数基本上归结为 opportunity cost - 还有许多其他语言功能和增强功能提供让更多用户受益。还有一个考虑是,infoof 语法可能复杂、令人困惑,并且最终不如使用基于字符串的反射强大。它也不能完全替代反射,因为在许多情况下,正在操作的元数据在编译时是未知的。

    但是,一切都不会丢失,您可以使用许多技巧来执行稍微安全的反射,从而利用 C# 语言的功能。例如,我们可以利用 lambda 表达式和表达式树来提取 MemberInfo 信息。一个简单的例子是:

    public static class MethodExt {
        static MethodInfo MemberInfo(Action d) {
           return d.Method;
        }
        // other overloads ...
    }
    

    当你传入一个(非匿名的)动作委托时它会起作用:

    MethodInfo mi = MethodExt.MemberInfo( Object.ToString );
    

    使用表达式树的上述实现可以更加健壮和灵活,但也更加复杂。它可以用来表示成员和属性访问、索引器等。

    所有这些“花哨”方法的主要问题是,它们会让习惯于看到传统反射代码的开发人员感到困惑。它们也不能处理所有情况,这常常导致传统反射代码和花哨的表达式树代码的不幸混合。 就个人而言,虽然这些技术很有趣且很有创意,但最好在生产代码中避免使用它。

    【讨论】:

    • D 声称有编译时反射! :)
    【解决方案4】:

    我自己使用一种从匿名方法中读取 IL 的方法(使用 Mono.Reflection 命名空间)并获取在匿名方法中找到的最后一个标记的信息。这往往是获取诸如add_EventHandlerset_Property 或捕获的局部变量之类的信息的唯一方法。要实际获取属性,我使用表达式树。

    我使用的语法是 Reflect.Member<T>.InfoOf<TMember>(Func<T,TMember> memberfunc),其中 Member 被替换为我感兴趣的类型。它确实很冗长,但它让用户确切地知道代码试图做什么。我也有 Reflect.Member 样式用于静态和构造函数之类的东西。 这里是相关代码sn -p::

    internal static MemberInfo GetLastMemberOfType(MethodBase method, MemberTypes memberType)
        {
            var instructions = method.GetInstructions();
            var operandtype = memberType == MemberTypes.Field ? OperandType.InlineField : OperandType.InlineMethod; 
            for (int i = instructions.Count-1; i > -1 ; i--)
            {
                if (instructions[i].OpCode.OperandType == operandtype)
                {
                    return instructions[i].Operand as MemberInfo;
                }
            }
            return null;
        }
    

    它会取代基于字符串的反射吗?绝对不。当我重构接口时,它是否使我的代码更安全?绝对地。 它会与我正在开发的产品一起提供吗?可能不是。

    【讨论】:

      猜你喜欢
      • 2011-01-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-02
      • 2010-09-26
      • 2011-03-18
      • 1970-01-01
      • 2018-08-06
      相关资源
      最近更新 更多