【问题标题】:Compile-time validation of the caller, or is it possible to extend C# compiler?调用者的编译时验证,或者是否可以扩展 C# 编译器?
【发布时间】:2012-12-28 08:22:49
【问题描述】:

考虑这个方法和描述:

[Description("It must be called from a property, else it is a runtime error.")]
protected T Load<T>()
{
   return InternalLoad<T>();
}

这个方法的设计要求调用者必须是一个属性,否则InternalLoad会抛出一个异常。它使用StackFrame获取调用者名称,如果不是get_&lt;PropertyName&gt;set_&lt;PropertyName&gt;的形式,则抛出异常。这一切都发生在我不喜欢的运行时。

我想知道是否有任何方法可以确保在编译时调用者始终是一个属性。换句话说,应该只允许属性调用此方法。有没有办法在编译时进行检查?

作为最后的手段,是否可以扩展 C# 编译器以使用自定义属性(例如 CallableFromAttribute)来确保这一点?

我想让它尽可能灵活:

[CallableFrom(Caller.Property)] //Caller is an enum
protected T Load<T>()
{
   return InternalLoad<T>();
}

[CallableFrom(Caller.Property | Caller.Method)]
protected T SomeOtherLoad<T>()
{
  //code
}

然后

public string Method()
{
    var x = this.SomeOtherLoad<string>(); //okay
    var y = this.Load<string>();          //compilation error !!
}

如果有任何混淆,请告诉我。我会澄清的。 :-)


我需要这个功能,因为我正在尝试实现一个名为PropertyManager 的类,它作为其他需要定义属性的类的 base 类。这个类的典型用法是这样的:

public sealed Vendor : PropertyManager
{
    public string VendorName
    {
       get { return this.Load<string>(); }
       set { this.Store(value); }
    }
    public DateTime Created
    {
       get { return this.Load<DateTime>(); }
       set { this.Store(value); }
    }
}

这里的LoadStore 方法在基类中定义,发现调用它们的属性的名称;将该名称视为 key,它从字典中读取关联的值(在 Load 的情况下),或写入它(在 Store 的情况下)。它引发属性更改和更改事件。它还支持撤消,因为ProperyMananger 可以轻松跟踪对属性所做的所有更改。

【问题讨论】:

  • 在我看来,您应该创建构建后任务来检查您的程序集并注入调用者检查。可能是Mono.Cecil 会帮助你。
  • 我认为在使用新的 roslyn 编译器服务时也许可以做到这一点,但我认为这样做永远不会得到回报。
  • 创建自定义 FxCop 规则似乎是可行的方法。
  • 这是一个非常糟糕的主意。不分享您为什么需要这样做以便我们可以提供更好的建议,这是一个过于本地化的问题的缩影。
  • @Nawaz 如果您可以在您的开发系统上安装 .NET Framework 4.5,您可以通过将&lt;UseHostCompilerIfAvailable&gt;false&lt;/UseHostCompilerIfAvailable&gt; 添加到您的项目文件中来让 VS 2010 使用该编译器。它有一些潜在的性能缺陷,但我在使用时没有注意到。

标签: c# validation compiler-construction attributes compile-time


【解决方案1】:

不,在编译时没有这种可能性。不可能:所有此类编译时检查都基于方法是否可以从访问它的方法访问,而不是调用它的方法。如果属性设置器通过委托公开Load,那么即使在理论上修改过的编译器中,也无法在编译时检查除了另一个属性设置器之外没有人使用该委托。

我不确定您为什么要这样做,所以我假设您的检查是必要的,并且您的运行时检查可以准确地验证您需要它做什么。如果这个假设是错误的,可能会有一些选择,但你提出的问题根本不可能。

【讨论】:

    猜你喜欢
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-29
    相关资源
    最近更新 更多