【问题标题】:Is there a delegate available for properties in C#?C# 中是否有可用于属性的委托?
【发布时间】:2008-11-14 12:50:57
【问题描述】:

给定以下类:

class TestClass {
  public void SetValue(int value) { Value = value; }
  public int Value { get; set; }
}

我可以的

TestClass tc = new TestClass();
Action<int> setAction = tc.SetValue;
setAction.Invoke(12);

这一切都很好。是否可以使用属性而不是方法来做同样的事情?最好使用.net内置的东西。

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    您可以使用反射创建委托:

    Action<int> valueSetter = (Action<int>)Delegate.CreateDelegate(typeof(Action<int>), tc, tc.GetType().GetProperty("Value").GetSetMethod());
    

    或为设置属性的匿名方法创建一个委托;

    Action<int> valueSetter = v => tc.Value = v;
    

    编辑:对 CreateDelegate() 使用了错误的重载,需要使用以对象为目标的重载。固定。

    【讨论】:

    • 鉴于 C# 应该是我的第一语言,我真的希望我能理解这些东西(使用反射创建委托)——听起来很棒
    • 对于 .net 2.0,可以执行 Action valueSetter = delegate(int value) { tc.Value = value; }
    • @Robert,您可以使用 C# 3.0 编译器来定位 .Net 2.0,没有理由坚持使用 C# 2.0 编译器;)
    • FWIW,我很好奇,并对上面给出的两种方法进行了基准测试(除了因为我的目标是 .Net 2.0,我使用 Action valueSetter = delegate(int v) { tc.Value = v; }; 而不是你给的 lambda)。编译时类型和名称检查(匿名委托 / lambda 版本)的权衡是它需要两倍的时间,因为代码调用了一个调用属性设置器的委托。第一种方法直接调用属性设置器,因此虽然您没有进行编译时检查,但您获得了两倍的速度,这对于我的特定方法来说意义重大。
    【解决方案2】:

    有三种方法可以做到这一点;第一种是使用GetGetMethod()/GetSetMethod() 并使用Delegate.CreateDelegate 创建一个委托。第二个是 lambda(反射没有多大用处!)[即x=>x.Foo]。第三个是通过表达式(.NET 3.5)。

    lambda 是最简单的;-p

        class TestClass
        {
            public int Value { get; set; }
        }
        static void Main()
        {
            Func<TestClass, int> lambdaGet = x => x.Value;
            Action<TestClass, int> lambdaSet = (x, val) => x.Value = val;
    
            var prop = typeof(TestClass).GetProperty("Value");
            Func<TestClass, int> reflGet = (Func<TestClass, int>) Delegate.CreateDelegate(
                typeof(Func<TestClass, int>), prop.GetGetMethod());
            Action<TestClass, int> reflSet = (Action<TestClass, int>)Delegate.CreateDelegate(
                typeof(Action<TestClass, int>), prop.GetSetMethod());
        }
    

    显示用法:

            TestClass foo = new TestClass();
            foo.Value = 1;
            Console.WriteLine("Via property: " + foo.Value);
    
            lambdaSet(foo, 2);
            Console.WriteLine("Via lambda: " + lambdaGet(foo));
    
            reflSet(foo, 3);
            Console.WriteLine("Via CreateDelegate: " + reflGet(foo));
    

    请注意,如果您希望委托指向特定实例,您可以对 lambda 使用闭包,或者接受和实例的 CreateDelegate 的重载。

    【讨论】:

    【解决方案3】:

    属性实际上是 .Net 中方法的包装器,因此使用反射您应该能够获取委托(set_PROPERTY 和 get_PROPERTY)然后执行它们...

    System.Reflection.PropertyInfo

    如果有两种方法可用于获取/设置值 - GetGetMethod 和 GetSetMethod。

    所以你可以写:

    var propertyInfo = typeof (TestClass).GetProperty ("Value");
    
    var setMethod = property.GetSetMethod (); // This will return a MethodInfo class.
    

    【讨论】:

    • 尽管 C# 规范为任何属性 P 保留了 get_P 和 set_P 方法,但它并不要求实现将这些方法用于属性。这使它成为一个实现细节。不要依赖未记录的实现细节。
    • 通过使用 PropertyInfo 类和 GetGet/SetMethod 不再是实现问题。它是当时框架的一部分。
    猜你喜欢
    • 2011-12-04
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    相关资源
    最近更新 更多