【发布时间】: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_<PropertyName>或set_<PropertyName>的形式,则抛出异常。这一切都发生在我不喜欢的运行时。
我想知道是否有任何方法可以确保在编译时调用者始终是一个属性。换句话说,应该只允许属性调用此方法。有没有办法在编译时进行检查?
作为最后的手段,是否可以扩展 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); }
}
}
这里的Load 和Store 方法在基类中定义,发现调用它们的属性的名称;将该名称视为 key,它从字典中读取关联的值(在 Load 的情况下),或写入它(在 Store 的情况下)。它引发属性更改和更改事件。它还支持撤消,因为ProperyMananger 可以轻松跟踪对属性所做的所有更改。
【问题讨论】:
-
在我看来,您应该创建构建后任务来检查您的程序集并注入调用者检查。可能是Mono.Cecil 会帮助你。
-
我认为在使用新的 roslyn 编译器服务时也许可以做到这一点,但我认为这样做永远不会得到回报。
-
创建自定义 FxCop 规则似乎是可行的方法。
-
这是一个非常糟糕的主意。不分享您为什么需要这样做以便我们可以提供更好的建议,这是一个过于本地化的问题的缩影。
-
@Nawaz 如果您可以在您的开发系统上安装 .NET Framework 4.5,您可以通过将
<UseHostCompilerIfAvailable>false</UseHostCompilerIfAvailable>添加到您的项目文件中来让 VS 2010 使用该编译器。它有一些潜在的性能缺陷,但我在使用时没有注意到。
标签: c# validation compiler-construction attributes compile-time