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

C# 如何为.NET属性创建委托?,c#,vb.net,delegates,C#,Vb.net,Delegates,我正在尝试为以下对象创建委托(作为测试): 我的直觉尝试是这样声明代理: Public Delegate Function Test() As String Dim t As Test = AddressOf e.PropertyName List<Func<int>> funcs = new List<Func<int>>(); foreach (var e in Collection) funcs.Add(new Func<in

我正在尝试为以下对象创建委托(作为测试):

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

Public Delegate Function Test() As String
Dim t As Test = AddressOf e.PropertyName
List<Func<int>> funcs = new List<Func<int>>();
foreach (var e in Collection)
   funcs.Add(new Func<int>(() => e.Property));
并像这样实例化:

Public Delegate Function Test() As String
Dim t As Test = AddressOf e.PropertyName
List<Func<int>> funcs = new List<Func<int>>();
foreach (var e in Collection)
   funcs.Add(new Func<int>(() => e.Property));
但这带来了一个错误:

方法“Public Overridable ReadOnly PropertyName()作为 字符串“”没有签名 与委托的委托兼容 函数Test()作为字符串'

因此,因为我在处理一处房产,我尝试了以下方法:

Public Delegate Property Test() As String
但这会引发一个编译器错误

所以问题是,如何为属性生成委托


请参阅此链接:

这里有一个C#示例,但所有类型都是相同的:

首先创建接口(委托)。请记住,附加到委托的方法必须返回相同的类型,并采用与委托声明相同的参数。 不要将委托定义在与事件相同的范围内

public delegate void delgJournalBaseModified();        
基于委托生成事件:

public static class JournalBase {
    public static event delgJournalBaseModified evntJournalModified;
};
定义一个方法,该方法可以绑定到具有与委托相同接口的事件

void UpdateEntryList()
{
}
将方法绑定到事件。在触发事件时调用该方法。您可以将尽可能多的方法绑定到事件。我不知道限制。这可能有点疯狂

 JournalBase.evntJournalModified += new delgJournalBaseModified(UpdateEntryList);
这里发生的是,该方法被添加为事件的回调。触发事件时,将调用您的方法

接下来,我们创建一个方法,该方法将在调用时触发事件:

public static class JournalBase {
    public static  void JournalBase_Modified()
    {
    if (evntJournalModified != null)
        evntJournalModified();
    }
};

然后,您只需在代码中的某个地方调用方法--JournalBase_Modified(),所有与事件相关的方法也会一个接一个地被调用。

使用AddressOf是个问题-如果您在编译时知道道具名称,您可以(至少在C#中)使用anon方法/lambda:

Test t = delegate { return e.PropertyName; }; // C# 2.0
Test t = () => e.PropertyName; // C# 3.0
我不是VB专家,但reflector声称这与:

Dim t As Test = Function 
    Return e.PropertyName
End Function
这样行吗


原始答复:

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

使用系统;
运用系统反思;
福班
{
公共字符串条{get;set;}
}
班级计划
{
静态void Main()
{
PropertyInfo prop=typeof(Foo).GetProperty(“Bar”);
Foo-Foo=新的Foo();
//创建一个开放的“getter”委托
Func getForAnyFoo=(Func)
CreateDelegate(typeof(Func),null,
prop.getMethod());
Func getForFixedFoo=(Func)
CreateDelegate(typeof(Func),foo,
prop.getMethod());
Action setForAnyFoo=(操作)
CreateDelegate(typeof(Action),null,
prop.GetSetMethod());
操作设置为FixedFoo=(操作)
CreateDelegate(typeof(Action),foo,
prop.GetSetMethod());
setForAnyFoo(foo,abc);
Console.WriteLine(getForAnyFoo(foo));
设置为固定foo(“def”);
WriteLine(getForFixedFoo());
}
}
以下是C#/.NET 2.0版本:

使用系统;
运用系统反思;
班级计划
{
私有委托无效设置值(T值);
私有委托T GetValue();
私家班
{
私人字符串(u bar),;
公共字符串栏
{
获取{return\u bar;}
设置{u bar=value;}
}
}
静态void Main()
{
Foo-Foo=新的Foo();
类型=类型(Foo);
PropertyInfo属性=type.GetProperty(“Bar”);
//塞特
MethodInfo MethodInfo=property.GetSetMethod();
设置值设置值=
(SetValue)Delegate.CreateDelegate(typeof(SetValue)、foo、methodInfo);
设定值(“abc”);
//吸气剂
methodInfo=property.getMethod();
GetValue GetValue=
CreateDelegate(typeof(GetValue)、foo、methodInfo);
字符串myValue=getValue();
//输出结果
控制台写入线(myValue);
}
}

同样,“Delegate.CreateDelegate”是这个示例的基础。

我刚刚创建了一个性能非常好的助手: 它不使用IL/Emit方法,而且速度非常快

由oscilatingcretin 2015/10/23编辑

源代码包含一些必须删除的大小写问题和特殊的
=“”
。在link-rot出现之前,我想我应该发布一个源代码的清理版本,以便轻松复制意大利面,以及如何使用它的示例

修订来源

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; }
    }
}
这是个好主意

Test t = () => e.PropertyName; // C# 3.0
但是,如果您正在做这样的事情,请小心:

Public Delegate Function Test() As String
Dim t As Test = AddressOf e.PropertyName
List<Func<int>> funcs = new List<Func<int>>();
foreach (var e in Collection)
   funcs.Add(new Func<int>(() => e.Property));
将始终返回集合中最后一个对象的属性值

在这种情况下,您应该调用方法:

foreach (var e in Collection)
   funcs.Add(new Func<int>(e.GetPropValue));
foreach(集合中的变量e)
funcs.Add(新函数(e.GetPropValue));
VB版本:

Dim prop As PropertyInfo = GetType(foo).GetProperty("bar")
Dim foo1 As New foo

Dim getForAnyFoo As Func(Of foo, String) = TryCast([Delegate].CreateDelegate(GetType(Func(Of foo, String)), Nothing, prop.GetGetMethod()), Func(Of foo, String))

Dim setForAnyFoo As Action(Of foo, String) = TryCast([Delegate].CreateDelegate(GetType(Action(Of foo, String)), Nothing, prop.GetSetMethod()), Action(Of foo, String))

Dim getForFixedFoo As Func(Of String) = TryCast([Delegate].CreateDelegate(GetType(Func(Of String)), foo1, prop.GetGetMethod()), Func(Of String))

Dim setForFixedFoo As Action(Of String) = TryCast([Delegate].CreateDelegate(GetType(Action(Of String)), foo1, prop.GetSetMethod()), Action(Of String))

    setForAnyFoo(foo1, "abc")
    Debug.WriteLine(getForAnyFoo(foo1))

    setForFixedFoo("def")
    Debug.WriteLine(getForFixedFoo())

我没有投你反对票,但问题涉及到房地产。。。我事后才明白。谢谢你没有投票否决我。看起来我没有检查问题的上下文就回答了。。。愚蠢的我。谢谢-我在.NET2.0中遇到了一个有问题的项目,我会看看类似的东西是否有效,并在这里给出反馈(否则可能是我链接到的详细解决方案出现的原因)。它似乎有效(尚未进行广泛测试),但我想知道您是否可以帮助解决这个问题。我需要在不使用硬编码字符串的情况下获取属性。问题是,我需要PropertyInfo来获取get方法,而我无法从用于更新的tanks的属性addressOfThanks获取该方法-不幸的是,VB.NET不支持匿名方法-我想唯一的解决方案是为每个属性创建一个函数包装器,并为此创建一个委托(与reflector代码所做的差不多).VB.NET支持lambda表达式(但它们必须返回一个值)-应该注意的是,lambda直到VB2008才存在于VB中,即使在VB2010之前,它们也只是单行。您的这个属性访问器太棒了!我的新应用程序基于您的属性访问器