如何将所有委托方法放入字典中?
How to put all delegate methods into a dictionary?
我正在研究一个缓存解决方案,以获取 class 的所有 属性 字段,从中创建 getter 和 setter 委托,并存储它们。
我现在是这样做的:
// entity is a class with a single public property called 'Name'
var entity = new Entity("Cat");
var nameProp = typeof(Entity)
.GetProperties()
.Single(x => x.Name == nameof(Entity.Name));
// getting getter and setter methods
var namePropGetter = nameProp.GetGetMethod();
var namePropSetter = nameProp.GetSetMethod();
// creating delegates for getter and setter methods
var namePropGetterDelegate = (Func<Entity, string>)Delegate.CreateDelegate(typeof(Func<Entity, string>), namePropGetter);
var namePropSetterDelegate = (Action<Entity, string>)Delegate.CreateDelegate(typeof(Action<Entity, string>), namePropSetter);
所有 getter 将存储在一个词典中,所有 setter 将存储在另一个词典中。这将使我能够快速获取或设置对象的值,而不是使用传统的 PropertyField.GetValue()
或 PropertyField.SetValue()
.
唯一的问题是 getter 和 setter 委托的存储。
我尝试将所有 getter 存储到 Func<TargetClass, object>
并将 setter 存储到 Action<TargetClass, object>
中,如下所示:
var getterDelegate = (Func<Entity, object>)Delegate.CreateDelegate(typeof(Func<Entity, object>), namePropGetter);
var setterDelegate = (Action<Entity, object>)Delegate.CreateDelegate(typeof(Action<Entity, object>), namePropSetter);
但它会给我以下错误:
Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
将所有内容存储在 Delegate
中会迫使我使用 DynamicInvoke()
,这首先违背了缓存所有内容的目的,因为它很慢。
发生错误是因为您将错误的类型传递给 Delegate.CreateDelegate
。例如,对于 Int32
属性 的 getter,您应该传递 Func<Entity, Int32>
而不是 Func<Entity, object>
。这可以通过 typeof(Func<,>).MakeGenericType(Entity, propType)
.
来实现
如果您想要每个 属性 名称的委托字典,您应该使用 Dictionary<string, Delegate>
,然后在调用它之前将 Delegate
转换为特定的委托类型:
var gettersDictionary = new Dictionary<string, Delegate>();
var settersDictionary = new Dictionary<string, Delegate>();
foreach (var prop in typeof(Entity).GetProperties())
{
var getterDelegate = Delegate.CreateDelegate(
typeof(Func<,>).MakeGenericType(typeof(Entity), prop.PropertyType),
prop.GetGetMethod());
gettersDictionary.Add(prop.Name, getterDelegate);
var setterDelegate = Delegate.CreateDelegate(
typeof(Action<,>).MakeGenericType(typeof(Entity), prop.PropertyType),
prop.GetSetMethod());
settersDictionary.Add(prop.Name, setterDelegate);
}
T GetPropValue<T>(Entity entity, string name)
{
var getter = (Func<Entity, T>) gettersDictionary[name];
return getter(entity);
}
void SetPropValue<T>(Entity entity, string name, T value)
{
var setter = (Action<Entity, T>) settersDictionary[name];
setter(entity, value);
}
我认为您根本不需要与 Delegate
打交道。您可以存储 Delegate
的集合,但是如果您必须以某种方式知道每个委托的 "real" 类型以便您可以对其进行转换,那么这没有任何用处。这往往 运行 撞墙。如果为了使用每个集合,您必须已经知道其基础类型,那么存储一些通用类型的集合是没有意义的。 (如果我们只是要转换为预期的类型,我们可以使用 Dictionary<string, object>
。)
以 属性 名称作为键的 getter 的字典如下所示:
var getters = Dictionary<string, Func<Entity, object>>();
为属性存储getter(PropertyInfo
通过反射发现)
getters.Add(property.Name, (entity) => property.GetValue(entity));
存储二传手比较复杂。您可以这样存储它们:
var setters = new Dictionary<string, Action<Entity, object>>();
...并添加一个 属性:
setters.Add(property.Name, (entity, value) => property.SetValue(entity, value);
但是假设您有一个实体、一个 属性 名称和一个要在 属性 上设置的值。您可以从字典中检索 Action
,但如果没有其他一些控件,则不能确定您打算设置的值是正确的类型。我们真的回到了同样的问题。我们将项目作为 "least common denominator" 类型存储在集合中,但为了使用它们,我们必须知道真实类型。多态性的好处是当我们只需要知道公分母时。
也许您已经确定了如何保持第二部分的正确性,但是很有可能一旦您有了字典,您将很难使用其中的内容。在那种情况下,可能有必要退后一步,看看是否有另一种方法可以解决不涉及此方法的更大问题。
我正在研究一个缓存解决方案,以获取 class 的所有 属性 字段,从中创建 getter 和 setter 委托,并存储它们。
我现在是这样做的:
// entity is a class with a single public property called 'Name'
var entity = new Entity("Cat");
var nameProp = typeof(Entity)
.GetProperties()
.Single(x => x.Name == nameof(Entity.Name));
// getting getter and setter methods
var namePropGetter = nameProp.GetGetMethod();
var namePropSetter = nameProp.GetSetMethod();
// creating delegates for getter and setter methods
var namePropGetterDelegate = (Func<Entity, string>)Delegate.CreateDelegate(typeof(Func<Entity, string>), namePropGetter);
var namePropSetterDelegate = (Action<Entity, string>)Delegate.CreateDelegate(typeof(Action<Entity, string>), namePropSetter);
所有 getter 将存储在一个词典中,所有 setter 将存储在另一个词典中。这将使我能够快速获取或设置对象的值,而不是使用传统的 PropertyField.GetValue()
或 PropertyField.SetValue()
.
唯一的问题是 getter 和 setter 委托的存储。
我尝试将所有 getter 存储到 Func<TargetClass, object>
并将 setter 存储到 Action<TargetClass, object>
中,如下所示:
var getterDelegate = (Func<Entity, object>)Delegate.CreateDelegate(typeof(Func<Entity, object>), namePropGetter);
var setterDelegate = (Action<Entity, object>)Delegate.CreateDelegate(typeof(Action<Entity, object>), namePropSetter);
但它会给我以下错误:
Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
将所有内容存储在 Delegate
中会迫使我使用 DynamicInvoke()
,这首先违背了缓存所有内容的目的,因为它很慢。
发生错误是因为您将错误的类型传递给 Delegate.CreateDelegate
。例如,对于 Int32
属性 的 getter,您应该传递 Func<Entity, Int32>
而不是 Func<Entity, object>
。这可以通过 typeof(Func<,>).MakeGenericType(Entity, propType)
.
如果您想要每个 属性 名称的委托字典,您应该使用 Dictionary<string, Delegate>
,然后在调用它之前将 Delegate
转换为特定的委托类型:
var gettersDictionary = new Dictionary<string, Delegate>();
var settersDictionary = new Dictionary<string, Delegate>();
foreach (var prop in typeof(Entity).GetProperties())
{
var getterDelegate = Delegate.CreateDelegate(
typeof(Func<,>).MakeGenericType(typeof(Entity), prop.PropertyType),
prop.GetGetMethod());
gettersDictionary.Add(prop.Name, getterDelegate);
var setterDelegate = Delegate.CreateDelegate(
typeof(Action<,>).MakeGenericType(typeof(Entity), prop.PropertyType),
prop.GetSetMethod());
settersDictionary.Add(prop.Name, setterDelegate);
}
T GetPropValue<T>(Entity entity, string name)
{
var getter = (Func<Entity, T>) gettersDictionary[name];
return getter(entity);
}
void SetPropValue<T>(Entity entity, string name, T value)
{
var setter = (Action<Entity, T>) settersDictionary[name];
setter(entity, value);
}
我认为您根本不需要与 Delegate
打交道。您可以存储 Delegate
的集合,但是如果您必须以某种方式知道每个委托的 "real" 类型以便您可以对其进行转换,那么这没有任何用处。这往往 运行 撞墙。如果为了使用每个集合,您必须已经知道其基础类型,那么存储一些通用类型的集合是没有意义的。 (如果我们只是要转换为预期的类型,我们可以使用 Dictionary<string, object>
。)
以 属性 名称作为键的 getter 的字典如下所示:
var getters = Dictionary<string, Func<Entity, object>>();
为属性存储getter(PropertyInfo
通过反射发现)
getters.Add(property.Name, (entity) => property.GetValue(entity));
存储二传手比较复杂。您可以这样存储它们:
var setters = new Dictionary<string, Action<Entity, object>>();
...并添加一个 属性:
setters.Add(property.Name, (entity, value) => property.SetValue(entity, value);
但是假设您有一个实体、一个 属性 名称和一个要在 属性 上设置的值。您可以从字典中检索 Action
,但如果没有其他一些控件,则不能确定您打算设置的值是正确的类型。我们真的回到了同样的问题。我们将项目作为 "least common denominator" 类型存储在集合中,但为了使用它们,我们必须知道真实类型。多态性的好处是当我们只需要知道公分母时。
也许您已经确定了如何保持第二部分的正确性,但是很有可能一旦您有了字典,您将很难使用其中的内容。在那种情况下,可能有必要退后一步,看看是否有另一种方法可以解决不涉及此方法的更大问题。