簡體   English   中英

如何將所有委托方法放入字典?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM