如何为.NET属性创建委托?

Mat*_*ell 21 c# vb.net delegates

我正在尝试创建一个委托(作为测试):

Public Overridable ReadOnly Property PropertyName() As String
Run Code Online (Sandbox Code Playgroud)

我的直觉尝试是声明代表这样:

Public Delegate Function Test() As String
Run Code Online (Sandbox Code Playgroud)

并实例化如下:

Dim t As Test = AddressOf e.PropertyName
Run Code Online (Sandbox Code Playgroud)

但这会引发错误:

方法'Public Overridable ReadOnly Property PropertyName()As String'没有与委托'Delegate Function Test()As String'兼容的签名.

因为我正在处理一个属性我试过这个:

Public Delegate Property Test() As String
Run Code Online (Sandbox Code Playgroud)

但这会引发编译错误.

所以问题是,我如何为一个财产代表?


看到这个链接:

http://peisker.net/dotnet/propertydelegates.htm

Mar*_*ell 37

使用AddressOf解决问题 - 如果你在编译时知道prop-name,你可以(至少在C#中)使用anon-method/lambda:

Test t = delegate { return e.PropertyName; }; // C# 2.0
Test t = () => e.PropertyName; // C# 3.0
Run Code Online (Sandbox Code Playgroud)

我不是VB专家,但反射器声称这与以下相同:

Dim t As Test = Function 
    Return e.PropertyName
End Function
Run Code Online (Sandbox Code Playgroud)

那样有用吗?


原始答案:

您可以为属性创建委托Delegate.CreateDelegate; 这可以打开任何类型的实例,固定为单个实例 - 并且可以用于getter或setter; 我将在C#中给出一个例子......

using System;
using System.Reflection;
class Foo
{
    public string Bar { get; set; }
}
class Program
{
    static void Main()
    {
        PropertyInfo prop = typeof(Foo).GetProperty("Bar");
        Foo foo = new Foo();

        // create an open "getter" delegate
        Func<Foo, string> getForAnyFoo = (Func<Foo, string>)
            Delegate.CreateDelegate(typeof(Func<Foo, string>), null,
                prop.GetGetMethod());

        Func<string> getForFixedFoo = (Func<string>)
            Delegate.CreateDelegate(typeof(Func<string>), foo,
                prop.GetGetMethod());

        Action<Foo,string> setForAnyFoo = (Action<Foo,string>)
            Delegate.CreateDelegate(typeof(Action<Foo, string>), null,
                prop.GetSetMethod());

        Action<string> setForFixedFoo = (Action<string>)
            Delegate.CreateDelegate(typeof(Action<string>), foo,
                prop.GetSetMethod());

        setForAnyFoo(foo, "abc");
        Console.WriteLine(getForAnyFoo(foo));
        setForFixedFoo("def");
        Console.WriteLine(getForFixedFoo());
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 11

我只是创建了一个具有相当好性能的帮助器:http: //thibaud60.blogspot.com/2010/10/fast-property-accessor-without-dynamic.html 它不使用IL/Emit方法,它非常快!

由oscilatingcretin编辑2015/10/23

来源包含一些套管问题和特殊的=""必须删除.在链接腐烂之前,我想我会发布一个清理版本的源码,以便轻松复制意大利面,以及如何使用它的示例.

修改来源

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Tools.Reflection
{
    public interface IPropertyAccessor
    {
        PropertyInfo PropertyInfo { get; }
        object GetValue(object source);
        void SetValue(object source, object value);
    }

    public static class PropertyInfoHelper
    {
        private static ConcurrentDictionary<PropertyInfo, IPropertyAccessor> _cache =
            new ConcurrentDictionary<PropertyInfo, IPropertyAccessor>();

        public static IPropertyAccessor GetAccessor(PropertyInfo propertyInfo)
        {
            IPropertyAccessor result = null;
            if (!_cache.TryGetValue(propertyInfo, out result))
            {
                result = CreateAccessor(propertyInfo);
                _cache.TryAdd(propertyInfo, result); ;
            }
            return result;
        }

        public static IPropertyAccessor CreateAccessor(PropertyInfo PropertyInfo)
        {
            var GenType = typeof(PropertyWrapper<,>)
                .MakeGenericType(PropertyInfo.DeclaringType, PropertyInfo.PropertyType);
            return (IPropertyAccessor)Activator.CreateInstance(GenType, PropertyInfo);
        }
    }

    internal class PropertyWrapper<TObject, TValue> : IPropertyAccessor where TObject : class
    {
        private Func<TObject, TValue> Getter;
        private Action<TObject, TValue> Setter;

        public PropertyWrapper(PropertyInfo PropertyInfo)
        {
            this.PropertyInfo = PropertyInfo;

            MethodInfo GetterInfo = PropertyInfo.GetGetMethod(true);
            MethodInfo SetterInfo = PropertyInfo.GetSetMethod(true);

            Getter = (Func<TObject, TValue>)Delegate.CreateDelegate
                    (typeof(Func<TObject, TValue>), GetterInfo);
            Setter = (Action<TObject, TValue>)Delegate.CreateDelegate
                    (typeof(Action<TObject, TValue>), SetterInfo);
        }

        object IPropertyAccessor.GetValue(object source)
        {
            return Getter(source as TObject);
        }

        void IPropertyAccessor.SetValue(object source, object value)
        {
            Setter(source as TObject, (TValue)value);
        }

        public PropertyInfo PropertyInfo { get; private set; }
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

public class MyClass
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

MyClass e = new MyClass();
IPropertyAccessor[] Accessors = e.GetType().GetProperties()
    .Select(pi => PropertyInfoHelper.CreateAccessor(pi)).ToArray();

foreach (var Accessor in Accessors)
{
    Type pt = Accessor.PropertyInfo.PropertyType;
    if (pt == typeof(string))
        Accessor.SetValue(e, Guid.NewGuid().ToString("n").Substring(0, 9));
    else if (pt == typeof(int))
        Accessor.SetValue(e, new Random().Next(0, int.MaxValue));

    Console.WriteLine(string.Format("{0}:{1}",
        Accessor.PropertyInfo.Name, Accessor.GetValue(e)));
}
Run Code Online (Sandbox Code Playgroud)