Как привести подмножество словаря к типу, производному от Dictionary‹›

Чтобы упростить использование словаря определенного типа, я создал класс, производный от общего словаря‹>, для обработки различных элементов, полученных из общего базового класса:

//my base class holding a value
public abstract class A{ public int aValue; }

//derived classes that actually are stuffed into the dictionary
public class B : A {...}
public class C : A {...}

//wrapper class for dictionary
public class MyDict : Dictionary<string, A>;

//my class using the dictionary
public class MyClass {

  public MyDict dict = new MyDict();//use an instance of MyDict

  public MyClass() { ... //fill dict with instances of B and C }

  //function to return all elements of dict having a given value
  public MyDict GetSubSet(int testVal) {
    var ret = dict.Where(e => e.Value.aValue == testVal).
                       ToDictionary(k => k.Key, k => k.Value);
    return (MyDict) ret; // <- here I get a runtime InvalidCastException
  }
}

Перед тем, как обернуть общий словарь в класс MyDict, приведение было выполнено успешно (если я заменю все экземпляры MyDict на Dictionary<string,int>, код будет работать нормально, даже без приведения в операторе return).

Я также пытался привести результат, используя return ret as MyDict;, но это вернет нулевое значение. Кастинг через object следующим образом: return (MyDict) (object) ret; также завершается с ошибкой InvalidCastException.

Кто-нибудь знает, как правильно преобразовать/преобразовать возвращаемое значение?


person AstaDev    schedule 05.06.2013    source источник


Ответы (1)


Вы получаете недопустимое исключение приведения, потому что результат ToDictionary не равен MyDict. Чтобы решить эту проблему, добавьте в MyDict конструктор, который принимает IDictionary<string,A>, и верните результат вызова этого конструктора из вашего метода GetSubSet:

public class MyDict : Dictionary<string, A> {
    public MyDict() {
        // Perform the default initialization here
        ...
    }
    public MyDict(IDictionary<string,A> dict): base(dict) {
        // Initialize with data from the dict if necessary
        ...
    }
}
...
public MyDict GetSubSet(int testVal) {
    var ret = dict.Where(e => e.Value.aValue == testVal).
                   ToDictionary(k => k.Key, k => k.Value);
    return new MyDict(ret);
}
person Sergey Kalinichenko    schedule 05.06.2013
comment
Спасибо за эту подсказку, она работает. Но я пытался найти способ избежать копирования словаря из-за его влияния на производительность. Нет ли способа использовать Dictionary<string,A>, возвращаемый ToDictionary(...), напрямую в качестве возвращаемого значения? - person AstaDev; 06.06.2013
comment
@AstaDev Making new MyDict ничего не копирует, потому что словари передаются по ссылке. Он использует возвращаемое значение ToDictionary напрямую, без создания копии — он просто помещает его в оболочку. - person Sergey Kalinichenko; 18.06.2013