【问题标题】:How to refer to the a properties accessor and mutator (getter/setter)如何引用属性访问器和修改器(getter/setter)
【发布时间】:2013-05-08 17:06:00
【问题描述】:

我想知道是否有一种高性能的方式来引用属性 getter 或 setter。比如下面第二个示例类的详细信息如何填写

public class Example
{
    public Example()
    {
        Action<int> setter = SetX;
        Func<int> getter = GetX;
    }
    public int GetX() { return 0; }
    public void SetX(int value){}
}

public class Example2
{
    public Example2()
    {
        Action<int> setter = ...;
        Func<int> getter = ...;
    }
    public int X
    {
        get{ return 0; }
        set{}
    }
}

我知道我可以像这样自己创建 lamdas:Action&lt;int&gt; setter = x =&gt; X = x。然而,我希望这样做的原因之一是比较应用程序其他部分中的引用本身。所以我实际上希望使用引用来识别特定的属性。

例如,我希望这能成功:

var example = new Example();
Func<int> something = example.GetX;
Func<int> somethingElse = example.GetX;
bool equality = something.Equals(somethingElse);

仅适用于使用属性。

我想这可以通过反射来完成,但是在我的整个应用程序中,这些操作中的许多可能每秒发生 30 次左右,所以我很犹豫是否使用这样的解决方案,而不是仅仅声明 GetX 和SetX 方法,尽管这看起来很笨拙。

最终目标是创建一种语法上简单的方法来设置字段,并通知已链接的那些已设置字段,并避免使用字符串来完成它。这是一个不使用属性的示例,但是可以使用额外的抽象来建立链接

public class Example
{
    public event Action<Delegate> Change;

    int x = 0;
    public int GetX() { return x; }
    public void SetX(int value) 
    {
        SetField(ref x, value, GetX);
    }

    protected void SetField<T>(ref T t, T value, Func<T> getter)
    {
        if (!EqualityComparer<T>.Default.Equals(getter(), value))
        {
            t = value;
            if(Change != null)
                Change(getter);
        }
    }
}

var example = new Example();
example.Change += getter =>
{
    Func<int> getX = example.GetX;
    if (getter.Equals(getX)) 
    {
        this.Log("x changed to: " + getX());
    }
};

example.SetX(5); // change is logged

【问题讨论】:

  • “参考文献”是什么意思?目前还不清楚您要实现的目标。
  • @JonSkeet 如果他有方法(如第一个示例),他可以使用方法标识符而不调用它来获取引用该方法的委托。他希望(在示例 2 中)获得一个代表集合和/或获取属性操作的委托。据我所知,没有办法做到这一点。
  • @Servy:但这有什么帮助呢?这是目前还不清楚的。对同一个实例使用两次方法组转换仍将创建两个不同(但相等)的委托实例。 p.s.w.g. 的回答可能是这里想要的,但要求还不够清楚,我不能说...
  • @JonSkeet 我添加了一个例子来说明我的意思,如果需要,我可以更详细地了解我试图优雅地解决的实际问题,但我认为这可能是一个不同的问题,如果事实证明这是不可能的。
  • @MikeMcFarland:在两个委托实例之间使用== 可能是错误的方法。使用Equals 会更合适。您真的只需要比较参考文献吗?

标签: c# properties


【解决方案1】:

我认为反射是做到这一点的唯一方法:

public Example2()
{
    var prop = this.GetType().GetProperty("X");
    Action<int> setter = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), this, prop.GetSetMethod());
    Func<int> getter = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), this, prop.GetGetMethod());
}

但正如你所说,反射并不是特别快。您可以将内部 getter / setter 定义为方法并绑定到这些方法,但这也不是您所要求的:

public Example2()
{
    Action<int> setter = this.GetX;
    Func<int> getter = this.SetX;
}

private int GetX() { return 0; }
private void SetX(int value) { }

public int X 
{
    get { return GetX(); } 
    set { SetX(value); } 
}

【讨论】:

  • 感谢您向我展示了如何使用反射来做到这一点,我最终可能会测试使用它是否真的会影响性能,只是希望有一个我不知道的功能。能够在没有反射的情况下调用 GetGetMethod() 将是完美的:)
  • 实际上,在最后一个示例中,当类已经具有具有给定签名的确切名称 get_Xset_X 的方法时,引入属性 X 是非法的。但是例如将方法重命名为GetXSetX
  • @JeppeStigNielsen 我从来不知道它会抱怨——我认为它会将内部名称改为get_X_1 或类似的名称。感谢您的信息。
猜你喜欢
  • 2017-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-28
  • 2018-11-25
  • 1970-01-01
  • 1970-01-01
  • 2011-06-26
相关资源
最近更新 更多