[英]How to put all delegate methods into a dictionary?
我正在開發一個緩存解決方案來獲取類的所有屬性字段,從中創建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都存儲在一個Dictionary中,所有的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);
但它會給我以下錯誤:
無法綁定到目標方法,因為其簽名或安全透明性與委托類型的簽名或安全透明性不兼容。
將所有內容存儲在Delegate
中將迫使我使用DynamicInvoke()
,因為它很慢,所以它首先會破壞緩存所有內容的目的。
發生錯誤是因為您將不正確的類型傳遞給Delegate.CreateDelegate
。 例如,對於Int32
屬性的getter,您應該傳遞Func<Entity, Int32>
而不是Func<Entity, object>
。 這可以通過typeof(Func<,>).MakeGenericType(Entity, propType)
來實現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
集合,但是如果你必須以某種方式知道每個委托的“真實”類型以便你可以投射它,那就沒有任何好處。 這往往會碰壁。 存儲某些常見類型的集合是沒有意義的,如果為了使用每個類型,您必須已經知道它的基礎類型。 (如果我們要轉換為期望的類型,我們可以使用Dictionary<string, object>
。)
以屬性名稱為鍵的getter字典如下所示:
var getters = Dictionary<string, Func<Entity, object>>();
存儲屬性的getter(反射發現的PropertyInfo
)
getters.Add(property.Name, (entity) => property.GetValue(entity));
存儲setter更復雜。 你可以像這樣存儲它們:
var setters = new Dictionary<string, Action<Entity, object>>();
...並添加一個屬性:
setters.Add(property.Name, (entity, value) => property.SetValue(entity, value);
但是假設您有一個實體,一個屬性名稱以及您想要在該屬性上設置的值。 您可以從字典中檢索Action
,但如果沒有其他控件,則無法確定您要設置的值是否為正確的類型。 我們真的回到了同樣的問題。 我們將項目存儲為集合中的“最小公分母”類型,但為了使用它們,我們必須知道真實類型。 多態性的好處是我們需要知道的共同點。
也許你已經確定了如何保持第二部分,但是很有可能一旦你有了字典,你將很難使用其中的內容。 在這種情況下,可能需要退后一步,看看是否有另一種方法來解決不涉及這種方法的更大問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.