(C #), почему Visual Studio говорит, что это объект, а GetType говорит, что это Func <object> ?

C # вопрос новичка здесь. Следующий код (взятый из книги «C # From Novice to Professional» Кристиана Гросса, Apress) выдает ошибку:

<code>worksheet.Add("C3", CellFactories.DoAdd(worksheet["A2"], worksheet["B1"]));
</code>

Причина в том, что методDoAdd() не принимает данные аргументы.

<code>public static Func<object> DoAdd(Func<object> cell1, Func<object> cell2) {...}
</code>

VS утверждает, что оба аргумента в вызове метода имеют типobject тогда как метод принимает толькоFunc<object>, Ноvalue обоих элементов листа имеет типFunc<object>:

<code>worksheet.Add("A2", CellFactories.Static(10.0));
</code>

где этоStatic Метод просто возвращает заданное значение:

<code>public static Func<object> Static(object value) { return () => value; }
// return type= Func<object>
</code>

Когда я снимаюworksheet["A2"] какFunc<object>код работает.

Но есть кое-что, чего я не понимаю. Тип экземпляра объектаFunc<object>, Я использовалGetType() Метод, чтобы увидеть доказательство этого, и сравнить типы объектов исходных элементов с типами объекта приведения (который принят):

<code>Console.Writeline(worksheet["A2"].GetType());

// now cast to the correct type (why can't it do that implicitly, btw?)
Funk1 = worksheet["A2"] as Func<object>;

Console.Writeline(Funk1.GetType());
</code>

.. и они ВСЕ идентичны! (Тип =System.Func'1[System.Object])

И даже когда я использую.Equals() метод для сравнения обоих типов, он возвращаетtrue.

Тем не менее, VS видит первый экземпляр объекта как типobject в вызове метода. Зачем? Почему вызываемый метод "см." аргумент как тип, отличный от GetType () возвращает? (и если да, то что хорошего вGetType() метод?)

Большое спасибо за ваши советы / комментарии! (Изучать язык довольно сложно, если примеры из книги дают ошибку, а вы не видите причину - следовательно, у вас сложилось смутное впечатление, что что-то не так сGetType() или VS.)

Ответы на вопрос(3)

но здесь я попытаюсь объяснить простым языком.

Когда ты пишешьworksheet["A2"] вы действительно вызываете функцию-членworksheet

worksheet имеет функцию-член с именем[] который принимаетstring и возвращаетobject

Подпись функции-члена[] похожеobject this[string id]

Так что функцияworksheet["A2"] возвращает что-то, что являетсяobject, Это может бытьint илиstring или много других вещей. Все, что знает компилятор, это то, что это будетobject.

В этом примере он возвращаетFunc<object>, Это хорошо, потому чтоFunc<object> is object, Однако затем вы передаете результат этой функции в качестве параметра другой функции.

Проблема здесь в том, что компилятор знает только, чтоworksheet["A2"] возвращаетobject, Это так же конкретно, как может быть компилятор. Таким образом, компилятор видит, чтоworksheet["A2"] является объектом, и вы пытаетесь передать объект в функцию, которая не принимаетobject в качестве параметра.

Так что здесь вы должны сказать компилятору: "Эй, дурак, этоFunc<object>& Quot; приведение возвращенного объекта к правильному типу.

worksheet.Add("C3", CellFactories.DoAdd(worksheet["A2"], worksheet["B1"]));

может быть переписан как

worksheet.Add("C3", CellFactories.DoAdd((Func<object>)worksheet["A2"], (Func<object>)worksheet["B1"]));

Теперь компилятор знает это, хотя[] функция возвращаетobject, это может относиться к этому какFunc<object>.

примечание: вы, вероятно, делаете слишком много в одной строке. Это может быть трудно для людей читать в будущем.

Why does the called method 'see' the argument as a different type than the GetType() returns?

Компилятор знает только, чтоworksheet[] возвращает объект. Компилятор не может вызватьGetType() на это во время компиляции.

What good is the GetType() method?

Есть довольно много случаев использования и злоупотребленияGetType() метод, но это совершенно другое обсуждение. ;)

Таким образом, компилятор не предполагает ничего о типах. Этоgood thing потому что вы получаете ошибку времени компиляции, когда вы пытаетесь поместить этот квадратный колышек в круглое отверстие. Если компилятор не жаловался, эта ошибка возникнет во время выполнения, что означает, что вам, вероятно, потребуется модульный тест для обнаружения проблемы.

Вы можете обойти эту проблему, сказав компилятору "Я знаю, что эта вещьis круглый колышек, поверь мне. и тогда он скомпилируется. Если вы врете компилятору, вы получите ошибку во время выполнения при выполнении этого кода.

Это называется «статическая типизация». Противоположная философия называется «динамическая типизация». где проверки типов выполняются во время выполнения. Статика против динамики - это длительная дискуссия, и вам, вероятно, следует изучить ее самостоятельно, если вы заинтересованы.

 17 июн. 2009 г., 18:59
+1: это хорошее прямое объяснение.

hereas the method accepts only Func. But the value of both worksheet elements is of type Func

Да, но объявленный типobject, Компилятор не может знать, что фактический тип времени выполнения будетFunc<object>, так что явное приведение необходимо.

 17 июн. 2009 г., 18:54
+1 Правильно, но можно использовать еще несколько объяснений.

dynamic typing а такжеstatic typing, Индексатор для вашегоworksheet Объект, скорее всего, имеет статический типobject.

public object this[string cell]{get{...}set{...}}

Потому что все объекты в C #унаследовать от типаobjectссылка на объект, хранящаяся в ячейке, может быть ссылкой наany объект.

То есть, потому что делегат (такой какFunc<T>) is objectможет храниться вobject ссылка:

Func<object> func = ()=>return "foo";
object o = func; // this compiles fine

И компилятор может понять все это, потому что он неявно понимает, что производный класс может быть сохранен в ссылке на базовый класс.

То, что компилятор не может сделать автоматически, это определить, что динамический тип, илиrun time type объекта есть.

Func<object> func = ()=>return "foo";
object o = func; // this compiles fine
func = o; // <-- ERROR

Компилятор не знает, чтоobject Хранится вo на самом деле типаFunc<object>, Это не должно отслеживать это. Это информация, которая должна быть проверена во время выполнения.

func = (Func<object>)o; // ok!

Приведенная выше строка кода компилируется во что-то похожее на это:

if(o == null)
    func = null;
else if(typeof(Func<object>).IsAssignableFrom(func.GetType()))
    __copy_reference_address__(func, o); // made up function!  demonstration only
else throw new InvalidCastException();

Таким образом, любое приведение (преобразование из одного типа в другой) может быть проверено во время выполнения, чтобы убедиться, что оно является действительным и безопасным.

 17 июн. 2009 г., 18:54
+1 Абсолютно верно, однако, возможно, слишком сложно объяснить кого-то новичка в C # и / или программировании.

Ваш ответ на вопрос