调用者的编译时验证,或者是否可以扩展c#编译器

本文关键字:是否 扩展 编译器 或者是 或者 编译 验证 调用者 | 更新日期: 2023-09-27 17:52:46

考虑这个方法和描述:

[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的类,它作为类,用于需要定义属性的其他类。该类的典型用法如下:

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方法,定义在基类中,发现它们被调用的属性的名称;将该名称视为,它从字典中读取相关值(在Load的情况下),或者向它写入值(在Store的情况下)。它引发属性改变和被改变的事件。它还支持撤消,因为ProperyMananger可以很容易地跟踪对属性所做的所有更改。

调用者的编译时验证,或者是否可以扩展c#编译器

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

我不知道你为什么要这样做,所以我假设你的检查是必要的,你的运行时检查正好验证了你所需要的。如果这个假设是错误的,可能有一些选择,但你的问题是根本不可能的。