2014-10-20 93 views
1

我想實現一個行爲類似於Dictionary<string, dynamic>的類,因爲動態關鍵字導致了由CAS問題導致的奇怪異常,我無法在項目的其他位置解析該異常。基本上我想要一個字典,允許獲取和設置異構值,而無需顯式投射。重新實現字典<string,dynamic>

我試圖得到一個內部的Dictionary<string, Tuple<Type, object>>,目的是爲了正確鑄造它。我想超載方括號的操作員獲取和設置。但是,我無法弄清楚這樣做的正確語法。我想做這樣的事情:

class DynDictionary<T> 
{ 
    private Dictionary<string, Tuple<Type, object>> _dict = new Dictionary<string, Tuple<Type, object>>(); 

    public T this[string key] 
    { 
    get { return (_dict[key].Item1)_dict[key].Item2; } 
    set { _dict[key] = new Tuple(typeof(value), value); } 
    } 
} 

當然,它不能編譯的原因有幾個。但是,我甚至無法使用泛型類來完成這項工作,而且我也不需要泛型類,因爲在實例化時我必須指定類型,這正是我想要避免的。

有沒有解決方案?我在幹什麼我不該碰的東西?

+3

你能表現出更多的周邊代碼來獲得完整的圖片? – 2014-10-20 13:52:02

+3

只是爲了檢查,你有沒有考慮過ExpandoObject? – 2014-10-20 13:59:47

+0

@manuFS:我沒有,但我有清楚的感覺,我會遇到與'dynamic'一樣的問題。例如,我看到ExpandoObject實現了IDynamicMetaObjectProvider,它是。只有NET 4,所以很可能會有同樣的問題。 – user1846231 2014-10-20 14:14:16

回答

2

不,沒有這樣的選擇。

正如你提到的,對於:

public T this[] { get; set; } 

你需要一些「通用性」,在外部範圍,爲this[]也無法對自己的通用。所以,你的課/不管是generic-<T>,並強制用戶不僅要指定T,而且要爲所有元素指定一個T。

對於Dictionary<string, Tuple<Type, object>>,你可以有最好的是:

public object this[] { get; set; } 
public IMyInterface this[] { get; set; } 

這是因爲在編譯的時候,你的整個字典類沒有對項目類型的任何信息。該代碼限於object,如Typle<Type,object>。你唯一能做的就是返回一個object,或者嘗試將它轉換成其他已知類型,比如接口。

如果從使用this[]辭職,你可以嘗試做一個「聰明的getter」:

public TValue GetItem<TValue>(TKey index) { ... } 
public void SetItem<TValue>(TKey index, TValue value) { ... } 

這將只是做所有的鑄件(return (TValue)tuple.Item2等)。但是,當「TValue」未知時,在上下文中使用時會出現一些問題,例如使用困難。所以,你也可能需要

public object GetItem(TKey index) { ... } 
public void SetItem(TKey index, object value) { ... } 

只是爲了避免繁瑣的GetItem<object>。當然,無論使用哪種TValue版本,用戶都需要明確地指定TValue(除了SetValue可能推斷的地方,不一定正確)。

現在,讓我們回到基礎。你有什麼想法

public T this[] { get; set; } 

anyways,hm?當你將Tuple中的Type和Object捆綁在一起時,你似乎希望能夠在Dictionary中包裝一個異源項目,對嗎?那麼,告訴我,如何最終用戶和/或代碼/編譯器將如何能夠猜到正在返回wnat:

var foo = myDictionary["bar"]; 

這將是foo變量的類型?編譯器無法猜測,因爲在編譯時myDictionary只知道它會保存一些Tuple<Type,object>,但它現在不包含任何東西。此外,它實際上還沒有存在,因爲它正在被編譯。根據你的Tuple的確切類型強制「返回值」是不可能的。

此外,爲什麼你甚至會在該元組中攜帶Type?保存在字典中的object總是知道它的類型。你不需要攜帶類型,你可以簡單地在該對象上使用.GetType(),但效果相同。如果你想保留上傳的類型信息(例如:有一個Bar從Foo繼承下來,upcast Bar作爲Foo並放入magiccontainer中,然後作爲Foo not Bar取回),那麼你的運氣有點不足。沒有幫助,並會返回你「動態對象」,這將知道自己是「酒吧」,並允許您動態調用所有酒吧方法。我認爲攜帶這種類型是完全沒有必要的,除非你有一些強大的屏蔽/隔離要求 - 但在這種情況下,簡單的「攜帶類型並鑄造」根本不會幫助。對於這樣的事情,你可能需要動態代理。由於我已經有了健談,最後(有點沒用,但你可能還是想聽到它)注意:實際上可以強制一個「強制類型」轉換爲存儲在「類型」中的類型。你可以用表達式來做到這一點。您可以動態構建Expression<>,將其與正確的Type對象綁定並調用。從https://stackoverflow.com/a/3983342/717732

借款代碼它看起來像:

public static ???? castAndReturn(object item, Type type) 
{ 
    var p = Expression.Parameter(typeof(object), "i"); 
    var c = Expression.Convert(p, type); 
    var ex = Expression.Lambda<Func<object, ????>>(c, p).Compile(); 

    return ex(item); 
} 

但同樣,有什麼返回類型你投入????佔位符,嗯?唯一的可能性是object,dynamic,或者定製的衆所周知的通用基礎類型。回到原點。 D'哦。抱歉。沒有,真的,方式。

+0

我很喜歡你的最後一點。我想它應該猜測與Dictionary 猜測的相同的東西,不管它是什麼。 – user1846231 2014-10-20 14:40:15

+0

@ user1846231:使用'Dictionary '它猜測它是....'dynamic'。說真的,不要開玩笑。語法'dynamic foo = 5; foo =新媽媽(); foo = 123.0'是正確的。使用.Net4,我們得到了一個新的名爲「dynamic」的神奇「數據類型」,您幾乎可以在任何可以使用像int或Mom這樣的普通數據類型的地方使用它。「Dictionary '不是魔法。它只是返回它的元素類型,而元素類型是'dynamic'。 – quetzalcoatl 2014-10-20 14:42:43

+0

我還添加了一個不是關於「真正的動態投射」,如果你想玩表情..但儘管可能和有趣的是,它在這個目前的問題中沒有任何收穫..呃,除非你想要沉重lambdaize /表達你的所有代碼。不是真的值得恕我直言。 '獲得(「酒吧」)'將更加可用,可讀和容易。 – quetzalcoatl 2014-10-20 14:45:20

0

這聽起來像你正試圖實現一個屬性容器暴露一個通用的索引器,這是(你知道)在C#中不可能的。但是,可以按照IEditorOptions界面中看到的模式實施類似的策略。特別要注意以下幾個特點:

  1. 與鍵關聯的強類型由創建EditorOptionKey<T>泛型類型,而不是使用只是一個字符串表示。
  2. GetOptionValue<T>SetOptionValue<T>方法會替換您當前使用的索引器屬性。這些方法的泛型類型參數是從作爲參數傳遞的EditorOptionKey<T>推斷出來的。

使用這個類可能看起來像以下(從DefaultOptions類使用多個字段)代碼:

IEditorOptions options = ...; 
bool replicate = options.GetOptionValue(DefaultOptions.ReplicateNewLineCharacterOptionId); 
options.SetOptionValue(DefaultOptions.IndentSizeOptionId, 2); 
options.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, true); 
相關問題