Invalid Cast Exception при использовании LINQ - PullRequest
0 голосов
/ 18 февраля 2010

Я классический новичок ...

Я могу скомпилировать свою программу, но получить предупреждение о недопустимости при запуске программы

что не так с моим кодом. я не знаю, что искать :(

Это мой код (.net 3.5)

class Element{
    private int i;
    public int I { get { return i; } set { i = value; } }
    private string s;
    public string S { get { return s; } set { s = value; } }

    public Element(string _s, int _i) {
        this.s = _s;
        this.i = _i;
    }
}
class myDict : Dictionary<string, Element> {
    public void afunction() { 

    }
}

class Program {
    static void Main(string[] args) {

        myDict myDict = new myDict();
        myDict.Add("a", new Element("x", 23));
        myDict.Add("b", new Element("y", 48));

       var sortedDict = ((from entry in myDict orderby entry.Key descending select entry).Take(10));

       myDict = (myDict)sortedDict.ToDictionary(v => v.Key, v => v.Value);
        foreach (KeyValuePair<string, Element> kvp in myDict) {
            System.Console.WriteLine("-> " +kvp.Key + " " + kvp.Value);
        }
        Console.ReadLine();
    }
}

спасибо! майкл:)

Ответы [ 6 ]

6 голосов
/ 18 февраля 2010

Hello

Привет.

Я классический новичок.

Добро пожаловать на борт.

Я могу скомпилировать свою программу, но получить недопустимое исключение приведения при запуске программы

Оператор приведения часто означает «Я сообщаю компилятору, что это преобразование допустимо. Если я ошибаюсь, выдает недопустимое исключение приведения во время выполнения».

что не так с моим кодом. Я не знаю, что искать.

Ну, тогда вместо того, чтобы вручать вам рыбу - состав словаря недействителен - давайте научим вас ловить рыбу.

Скомпилируйте вашу программу в режиме отладки и запустите ее в отладчике. Отладчик должен сломаться в точном месте исключения. Затем вы можете проанализировать, что не так на этом конкретном сайте.

Если по какой-то причине вы не можете запустить свой код в отладчике, скомпилируйте вашу программу в режиме отладки и запустите ее в обычном режиме. Когда вы получаете исключение, посмотрите на часть «трассировки стека» исключения. В нем должен быть номер строки сайта исключения, чтобы вы могли затем изучить этот код.

И если по какой-то причине вы не можете этого сделать, используйте сообщение об исключении, чтобы попытаться выяснить это. «Недопустимое исключение приведения» подразумевает, что плохое поведение является результатом оператора приведения. В вашей программе есть два места, где используется оператор приведения. Существует явное использование в приведении словаря, и есть неявное использование в цикле foreach.

Многие удивляются, узнав о последнем. Когда вы говорите

foreach(Giraffe giraffe in animals)

это на самом деле означает «бросить каждое животное в списке животных к Жирафу и дать недопустимое исключение приведения, если одним из них является Тигр, Валлаби или что-то в этом роде». Это не значит «игнорировать всех животных, которые не являются жирафами» - если вы этого хотите, то скажите

foreach(Giraffe giraffe in animals.OfType<Giraffe>())

Проблема почти наверняка будет в одном из этих двух мест.

2 голосов
/ 18 февраля 2010

Вызов ToDictionary возвращает Dictionary<string, Element>. То, что myDict является Dictionary<string, Element>, не означает, что Dictionary<string, Element> является myDict.

2 голосов
/ 18 февраля 2010

Вы не можете сделать это:

myDict = (myDict)sortedDict.ToDictionary(v => v.Key, v => v.Value);

Когда вы вызываете ToDictionary , вы создаете Dictionary<string, Element>, а не myDict экземпляр. Этот состав недействителен.

Однако нет никаких причин (в данном случае), чтобы сделать это. Вы можете просто использовать результаты sortedDict напрямую.

Если вы хотите сделать это, я бы порекомендовал добавить конструктор к myDict, который занимает IEnumerable<KeyValuePair<string,Element>>. Вы могли бы тогда сделать:

class myDict : Dictionary<string, Element> {
     public myDict() {}
     public myDict(IEnumerable<KeyValuePair<string, Element>> pairs)
     {
          foreach(var pair in pairs)
               this.Add(pair.Key, pair.Value); // Add in all elements
     }
}

Тогда вместо приведения вы можете сделать:

myDict myDict = new myDict();
myDict.Add("a", new Element("x", 23));
myDict.Add("b", new Element("y", 48));

var sortedDict = ((from entry in myDict orderby entry.Key descending select entry).Take(10));

myDict = new myDict(sortedDict);

Как говорится, подкласс Dictionary<TKey,TValue> является плохой идеей напрямую. Если вы хотите создать пользовательский словарь, вам следует заключить словарь фреймворка в свой собственный класс и вместо него реализовать IDictionary<TKey,TValue>.

2 голосов
/ 18 февраля 2010

Мне кажется, проблема в том, что вы приводите результат sortedDict.ToDictionary () как myDict.

myDict = (myDict)sortedDict.ToDictionary(v => v.Key, v => v.Value);
0 голосов
/ 18 февраля 2010

Ваша проблема в том, что вы не можете выполнить приведение обратно к myDict, поскольку это гораздо более специфичный класс, чем Dictionary

0 голосов
/ 18 февраля 2010

ToDictionary() не возвращает класс myDict, он возвращает класс Dictionary. Вы не можете разыграть от Dictionary до myDict, хотя, поскольку myDict происходит от Dictionary, вы можете разыграть другой способ.

...