私は(テストとして)デリゲートを作成しようとしています:
Public Overridable ReadOnly Property PropertyName() As String
私の直感的な試みは、次のようにデリゲートを宣言することでした。
Public Delegate Function Test() As String
そして、このようにインスタンス化します:
Dim t As Test = AddressOf e.PropertyName
しかし、これはエラーをスローします:
メソッド 'Public Overridable ReadOnly Property PropertyName()As String'には、デリゲート 'Delegate Function Test()AsString'と互換性のある署名がありません。
それで、私は不動産を扱っていたので、これを試しました:
Public Delegate Property Test() As String
しかし、これはコンパイラエラーをスローします。
だから問題は、どうすればプロパティのデリゲートを作成するのですか?
このリンクを参照してください:
AddressOfを使用した問題について-コンパイル時にprop-nameがわかっている場合は、(少なくともC#では)anon-method/lambdaを使用できます。
Test t = delegate { return e.PropertyName; }; // C# 2.0
Test t = () => e.PropertyName; // C# 3.0
私はVBの専門家ではありませんが、リフレクターはこれが次と同じであると主張しています:
Dim t As Test = Function
Return e.PropertyName
End Function
それは動作しますか?
元の答え:
プロパティのデリゲートは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());
}
}
かなり良いパフォーマンスのヘルパーを作成するだけです: 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; }
}
}
次のように使用します:
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)));
}
これがC#/。NET 2.0バージョンの Marc Gravellの応答 :
using System;
using System.Reflection;
class Program
{
private delegate void SetValue<T>(T value);
private delegate T GetValue<T>();
private class Foo
{
private string _bar;
public string Bar
{
get { return _bar; }
set { _bar = value; }
}
}
static void Main()
{
Foo foo = new Foo();
Type type = typeof (Foo);
PropertyInfo property = type.GetProperty("Bar");
// setter
MethodInfo methodInfo = property.GetSetMethod();
SetValue<string> setValue =
(SetValue<string>) Delegate.CreateDelegate(typeof (SetValue<string>), foo, methodInfo);
setValue("abc");
// getter
methodInfo = property.GetGetMethod();
GetValue<string> getValue =
(GetValue<string>) Delegate.CreateDelegate(typeof (GetValue<string>), foo, methodInfo);
string myValue = getValue();
// output results
Console.WriteLine(myValue);
}
}
繰り返しますが、「Delegate.CreateDelegate」がこの例の基本です。
これは良い考えです
Test t = () => e.PropertyName; // C# 3.0
ただし、次のようなことをしている場合は注意してください。
List<Func<int>> funcs = new List<Func<int>>();
foreach (var e in Collection)
funcs.Add(new Func<int>(() => e.Property));
これを呼び出す:
foreach(var f in funcs)
f();
コレクション内のlastオブジェクトのプロパティの値を常に返します
この場合、メソッドを呼び出す必要があります。
foreach (var e in Collection)
funcs.Add(new Func<int>(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())
これは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()-を呼び出すだけで、イベントに関連付けられているすべてのメソッドも次々に呼び出されます。