2009-06-30 4 views
0

у меня есть:IDictionary, словарь

IDictionary<string, IDictionary<string, IList<long>>> OldDic1; 

(только для целей иллюстрации, она конкретизируется и имеет значения - где-то еще)

Почему я могу это сделать?

Dictionary<string, IDictionary<string, IList<long>>> dic1 = 
    OldDic1 as Dictionary<string, IDictionary<string, IList<long>>>; 

В основном dic1 после выполнения этой строки имеет все значения от OldDic1; работает.

Однако, когда я делаю это:

Dictionary<string, Dictionary<string, List<long>>> dic1 = 
    OldDic1 as Dictionary<string, Dictionary<string, List<long>>>; 

Я получаю нулевой, это то же самое, как отливка, кроме него не врезаться, а вместо этого он возвращает нуль. Итак, вопрос в том, почему я не могу отнести его от интерфейсов к типам? есть ли решение, другое, а затем изменение того, как оно хранится в первую очередь?

+0

Кастинг немного запутанный. При выполнении такого рода приведения (или использования «как») в основном все, что вы делаете, это проверка того, действительно ли объект является указанным типом в хранилище. Вы не создаете новый объект с таким типом, вы просто проверяете. Если это неясно, попробуйте прочитать эту статью: http://blogs.msdn.com/ericlippert/archive/2009/03/19/representation-and-identity.aspx –

+0

Спасибо, отличная статья. – ra170

ответ

2

Вы можете повторно отображать внешний интерфейс/имя класса, а не общие параметры. Причина, по которой ваш второй актер не работает, - это та же причина, по которой вы не можете отбрасывать из одного типа массива в другой, даже если вы можете использовать «содержащиеся» объекты. Вот почему:

List<object> objects; 
List<string> strings; 

objects = strings as List<object>; 
// Uh oh, that's not a string! 
objects.Add(42); 

objects = new List<object> { "The", "answer", "is", 42 }; 
// Uh oh, now strings contains an integer? 
strings = objects as List<string>; 

То же самое произойдет в вашем втором случае. Вы могли бы добавить какой-то IDictionary в OldDic1, который на самом деле не Dictionary, а затем dic1 взорвется. Он будет иметь значение не Dictionary. Ruh roh!

Таким образом, если у вас есть контейнеры можно изменить с IList<X> к List<X> и обратно до тех пор, как X является идентичны для каждого.

+0

За исключением того, что вы можете использовать один тип массива для другого в C#, если типы элементов массива ссылочные типы, которые можно отличить. Преобразования массива ковариантны в C#, если типы элементов являются типами ссылок. Такая ковариация на самом деле не безопасна на типе! К сожалению, это было добавлено к системе типов. –

0

Поведение связано с as keyword в C#. Словарь - это не то же самое, что IDictionary.

Если вы выбрали другой способ, вы можете заставить его работать в следующей версии .NET, у которой увеличена поддержка covariance and contravariance.

Решение, которое вы, возможно, захотите определить: , почему вам нужно отдать конкретному словарю/списку, и если это необходимо, измените хранилище этого типа.

+0

Причина, по которой я должен отбрасывать конкретный тип, связана с DataContractJsonSerializer, для которого требуется тип. когда объект имеет тип conrete, я могу сказать dic1.GetType(), однако, если я это делаю на интерфейсах, DataContractJsonSeralizer .writeobject выдает исключение – ra170