【问题标题】:Compile Time Reflection in C#C# 中的编译时间反射
【发布时间】:2012-03-09 06:12:30
【问题描述】:

我经常编写必须使用魔术字符串来表达属性名称的 C# 代码。每个人都知道魔术弦的问题。它们很难重构,没有编译时检查,而且常常导致难以诊断的问题。然而,C#/.NET到处都使用它们来表示属性/类/方法名。

这个问题多年来一直存在,目前唯一可行的解​​决方案是使用表达式树,然后在运行时解析属性名称。这可以让您获得满意的编译时检查,但会使代码复杂化(需要表达式类型的参数),并且会产生运行时成本。

有谁知道 C#/.NET 是否曾经考虑过添加编译时反射来克服这个普遍存在的问题?

这似乎是一个简单的添加,它将是一个非破坏性的更改,它将极大地受益于许多开发人员。 typeof() 操作符已经执行了一种编译时反射形式,所以看起来像操作符 nameof() (或类似的东西)将是非常互补的。

此外,有谁知道此类功能存在任何潜在问题?

感谢您的帮助。

【问题讨论】:

标签: c# .net compile-time strong-typing magic-string


【解决方案1】:

Straight from the source - 这是 C# 语言设计者的博客文章,这篇文章中的“用户”提出了与您相同的问题并得到了回答。作者说,需要为您要请求的每个元数据项指定语法,这不是微不足道的 - 即。如果您想要“info-of”方法并且该方法已重载,您想要哪个重载?如果涉及泛型和显式接口实现怎么办?等等。事实证明,虽然由于这些原因,它在 2009 年被认为不值得实施,但我们将在 2015 年在 C# 6 中实现它 - 请参阅 C# Language Design Notes for Jul 9, 2014

【讨论】:

  • 嗯,这是一篇来自 C# 语言设计者的博客文章,内容涉及实现“infoof()”运算符的实际问题,该运算符的工作方式类似于 typeof,但适用于任何元数据(方法、属性等)。 OP 从文章中提出与“用户”相同的问题,“用户”得到所有答案。
  • 埃里克的回答似乎暗示使用表达式已经解决了这个问题。但微软的许多技术使用魔术字符串来表示类/属性:ASP .NET(Web Forms 和 MVC)、Silverlight、WPF、Winforms;他们都使用它们。更不用说您可能依赖的第三方开发人员了。如果你足够努力,你会发现也使用它们的核心库。对我来说,这似乎是一个比 async/await 关键字解决的问题更普遍的问题(而且更容易解决)。
  • 我不认为是帖子回答了为什么不能用于不能重载的属性。
  • 虽然这个答案已经有一年多了,而且这个链接很有帮助,但是如果你在这个网站上发布答案的基本部分会更好,或者你的帖子有被删除的风险See the FAQ where it mentions answers that are 'barely more than a link'.你如果您愿意,仍然可以包含该链接,但仅作为“参考”。答案应该是独立的,不需要链接。
【解决方案2】:

在 C# 6.0 中,添加了一个新运算符 nameof,它允许您在编译时获取属性、类、字段、事件和变量的名称。

Link to the design notes

编译器在设计时已经知道的信息不再反射!

【讨论】:

    【解决方案3】:

    我遇到了类似的问题。最近才发现.NET Framework 4.5 有一个称为Caller Info 属性的功能。通过使用这些,您可以在编译时获取有关方法调用者的信息。可以获取源码的文件路径,源码中的行号,调用者的成员名。

    public void DoProcessing()
    {
        TraceMessage("Something happened.");
    }
    
    public void TraceMessage(string message,
            [CallerMemberName] string memberName = "",
            [CallerFilePath] string sourceFilePath = "",
            [CallerLineNumber] int sourceLineNumber = 0)
    {
        Trace.WriteLine("message: " + message);
        Trace.WriteLine("member name: " + memberName);
        Trace.WriteLine("source file path: " + sourceFilePath);
        Trace.WriteLine("source line number: " + sourceLineNumber);
    }
    

    【讨论】:

      【解决方案4】:

      然而 C#/.NET 到处使用它们来表示属性/类/方法名称。

      首先:我不同意。有某些框架(例如 WebForms)到处都使用魔术字符串,但 C# 和 .NET 的基础库往往能很好地避免这些事情。

      其次:在许多使用魔术字符串的情况下,ReSharper 能够识别错误。这会很有帮助。

      最后:您所要求的可以通过 Roslyn 编译器实现,它承诺提供“编译即服务”。

      【讨论】:

      • 我同意核心 .NET 库远离魔术字符串,但是如果您完全看过 MVC3,哦,伙计,它的 MagicString 地狱 :) 感谢 ReSharper 能够告诉您,如果您在字符串参数中输入了错误的控制器或动作名称!
      • 编译器在编译期间已经知道所有相关信息,以使此功能成为可能。据我了解,Roslyn 只会让第 3 方在编译时更轻松地获得类似的代码洞察力。
      • @MgSam:Roslyn 似乎可以设置您自己的编译规则,因此可以想象它可以让您在代码中编写表达式树,然后将其转换为方法名称、控制器名称等. 在编译时。
      猜你喜欢
      • 2014-04-08
      • 1970-01-01
      • 2015-06-15
      • 2020-09-03
      • 1970-01-01
      • 2014-07-29
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      相关资源
      最近更新 更多