(C#)为什么Visual Studio说它是一个对象,而GetType说它是一个Func ?

时间:2020-12-20 15:50:22

C# newbie question here. The following code (taken from the book "C# From Novice to Professional" by Christian Gross, Apress) gives an error:

C#新手问题在这里。以下代码(取自Christian Gross,Apress的书“C#From Novice to Professional”)给出了一个错误:

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

The reason is that the method DoAdd() does not accept the given arguments.

原因是方法DoAdd()不接受给定的参数。

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

VS claims that both args in the method call above are of type object whereas the method accepts only Func<object>. But the value of both worksheet elements is of type Func<object>:

VS声称上面的方法调用中的两个args都是object类型,而该方法只接受Func 。但是两个工作表元素的值都是Func 类型:

worksheet.Add("A2", CellFactories.Static(10.0));

where this Static method just returns the given value:

这个静态方法只返回给定值:

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

When I cast worksheet["A2"] as Func<object>, the code does work.

当我将工作表[“A2”]转换为Func 时,代码确实有效。

But there is something I don't understand. The type of the object instance is Func<object>. I have used the GetType() method to see proof of this, and compare the object types of the original elements to that of the cast object (which IS accepted):

但有些事情我不明白。对象实例的类型是Func 。我已经使用GetType()方法来查看这个证明,并将原始元素的对象类型与强制转换对象的对象类型进行比较(可以接受):

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());

.. and they are ALL identical! (Type = System.Func'1[System.Object])

..他们都完全相同! (Type = System.Func'1 [System.Object])

And even when I use the .Equals() method to compare both types, it returns true.

即使我使用.Equals()方法比较两种类型,它也会返回true。

Yet, VS sees the first object instance as type object in the method call. Why? Why does the called method 'see' the argument as a different type than the GetType() returns? (and if so, what good is the GetType() method?)

然而,VS在方法调用中将第一个对象实例视为类型对象。为什么?为什么被调用的方法“看到”参数与GetType()返回的类型不同? (如果是这样,GetType()方法有什么用?)

Thanks a lot for your advice/comments! (It's kinda hard to learn the language if the book examples give an error and you don't see the reason - hence, got the vague impression that something is wrong either with GetType() or VS.)

非常感谢您的建议/意见! (如果书中的例子给出错误并且你没有看到原因,那么学习语言有点难度 - 因此,得到模糊的印象,即GetType()或VS出现问题。)

3 个解决方案

#1


You need to understand the difference between dynamic typing and static typing. The indexer for your worksheet object most likely has a static type of object.

您需要了解动态类型和静态类型之间的区别。工作表对象的索引器很可能具有静态类型的对象。

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

Because all objects in C# inherit from type object, the object reference stored in a cell can be a reference to any object.

因为C#中的所有对象都继承自类型对象,所以存储在单元格中的对象引用可以是对任何对象的引用。

That is, because a delegate (such as Func<T>) is an object, it can be stored in an object reference:

也就是说,因为委托(例如Func )是一个对象,它可以存储在一个对象引用中:

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

And the compiler can figure this all out, because it understands implicitly that a derived class can be stored in a reference to a base class.

编译器可以全部解决这个问题,因为它隐式地理解派生类可以存储在对基类的引用中。

What the compiler cannot do automatically, is determine what the dynamic type, or run time type of an object is.

编译器无法自动执行的操作是确定对象的动态类型或运行时类型。

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

The compiler doesn't know that the object stored in o is actually of type Func<object>. It's not supposed to keep track of this. This is information that must be checked at run time.

编译器不知道存储在o中的对象实际上是Func 类型。它不应该跟踪这个。这是必须在运行时检查的信息。

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

The above line of code compiles into something that behaves similarly to this:

上面的代码行编译成与此类似的行为:

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();

In this way, any cast (conversion from one type to another) can be checked at run time to make sure it's valid and safe.

通过这种方式,可以在运行时检查任何演员表(从一种类型转换为另一种类型)以确保其有效且安全。

#2


Others have given accurate and detailed answers, but here I will try to explain in simple language.

其他人给出了准确而详细的答案,但在这里我将尝试用简单的语言解释。

When you write worksheet["A2"] you really are calling a member function of worksheet

当你编写工作表[“A2”]时,你真的在​​调用工作表的成员函数

worksheet has a member function named [] that accepts a string and returns an object

工作表有一个名为[]的成员函数,它接受一个字符串并返回一个对象

The signature of the member function [] looks like object this[string id]

成员函数[]的签名看起来像对象[string id]

So the function worksheet["A2"] returns something that is an object. It could be an int or a string or many other things. All the compiler knows is that it will be an object.

因此函数工作表[“A2”]返回一个对象。它可以是int或字符串或许多其他东西。所有编译器都知道它将是一个对象。

In the example, you have it returning a Func<object>. This is fine, because Func<object> is an object. However, you then pass the result of that function in as a parameter to another function.

在该示例中,您将返回一个Func 。这很好,因为Func 是一个对象。但是,然后将该函数的结果作为参数传递给另一个函数。

The problem here is that the compiler only knows that worksheet["A2"] returns an object. That is as specific as the compiler can be. So the compiler sees that worksheet["A2"] is an object, and you are trying to pass the object to a function that does not accept object as a parameter.

这里的问题是编译器只知道工作表[“A2”]返回一个对象。这与编译器一样具体。因此编译器看到工作表[“A2”]是一个对象,并且您试图将该对象传递给不接受对象作为参数的函数。

So here you have to tell the compiler "hey dummy, that's a Func<object>" by casting the returned object to the correct type.

所以在这里你必须通过将返回的对象强制转换为正确的类型来告诉编译器“hey dummy,这是一个Func ”。

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

can be re-written as

可以重写为

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

Now the compiler knows that, even though the [] function returns an object, it can treat it like a Func<object>.

现在编译器知道,即使[]函数返回一个对象,它也可以将它视为Func

side note: You're probably doing too much on one line. That may be hard for people to read in the future.

旁注:你可能在一条线上做得太多了。人们今后可能难以阅读。

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

为什么被调用的方法“看到”参数与GetType()返回的类型不同?

The compiler only knows that worksheet[] returns an object. The compiler can not call GetType() on it at compile time.

编译器只知道worksheet []返回一个对象。编译器无法在编译时调用GetType()。

What good is the GetType() method?

GetType()方法有什么用?

There are quite a few uses and abuses of the GetType() method, but that is an entirely different discussion. ;)

GetType()方法有很多用途和滥用,但这是一个完全不同的讨论。 ;)

In summary, the compiler does not assume anything about types. This is a good thing because you get a compile time error when you try to fit this square peg into a round hole. If the compiler did not complain, this error would surface at run-time, which means you would probably need a unit test to detect the problem.

总之,编译器不会假设有关类型的任何内容。这是一件好事,因为当您尝试将此方形钉插入圆孔时,会出现编译时错误。如果编译器没有抱怨,则此错误将在运行时出现,这意味着您可能需要单元测试来检测问题。

You can get around this problem by telling the compiler "I know for a fact that this thing is a round peg, trust me." and then it will compile. If you lie to the compiler, you will get a run-time error when that code is executed.

你可以通过告诉编译器“我知道这个东西是一个圆形挂钩,相信我”来解决这个问题。然后它将编译。如果您对编译器撒谎,则在执行该代码时会出现运行时错误。

This is called "static typing". The opposing philosophy is called "dynamic typing" where type checks are done at run-time. Static vs dynamic is a lengthy debate and you should probably research it on your own if you're interested.

这称为“静态类型”。反对的哲学被称为“动态类型”,其中类型检查在运行时完成。静态与动态是一个冗长的争论,如果你感兴趣,你应该自己研究它。

#3


VS claims that both args in the method call above are of type object whereas the method accepts only Func. But the value of both worksheet elements is of type Func

VS声称上面的方法调用中的两个args都是object类型,而该方法只接受Func。但是两个工作表元素的值都是Func类型

Yes, but the declared type is object. The compiler can't know that the actual runtime type will be Func<object>, so an explicit cast is necessary.

是的,但声明的类型是对象。编译器无法知道实际的运行时类型将是Func ,因此需要进行显式转换。

#1


You need to understand the difference between dynamic typing and static typing. The indexer for your worksheet object most likely has a static type of object.

您需要了解动态类型和静态类型之间的区别。工作表对象的索引器很可能具有静态类型的对象。

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

Because all objects in C# inherit from type object, the object reference stored in a cell can be a reference to any object.

因为C#中的所有对象都继承自类型对象,所以存储在单元格中的对象引用可以是对任何对象的引用。

That is, because a delegate (such as Func<T>) is an object, it can be stored in an object reference:

也就是说,因为委托(例如Func )是一个对象,它可以存储在一个对象引用中:

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

And the compiler can figure this all out, because it understands implicitly that a derived class can be stored in a reference to a base class.

编译器可以全部解决这个问题,因为它隐式地理解派生类可以存储在对基类的引用中。

What the compiler cannot do automatically, is determine what the dynamic type, or run time type of an object is.

编译器无法自动执行的操作是确定对象的动态类型或运行时类型。

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

The compiler doesn't know that the object stored in o is actually of type Func<object>. It's not supposed to keep track of this. This is information that must be checked at run time.

编译器不知道存储在o中的对象实际上是Func 类型。它不应该跟踪这个。这是必须在运行时检查的信息。

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

The above line of code compiles into something that behaves similarly to this:

上面的代码行编译成与此类似的行为:

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();

In this way, any cast (conversion from one type to another) can be checked at run time to make sure it's valid and safe.

通过这种方式,可以在运行时检查任何演员表(从一种类型转换为另一种类型)以确保其有效且安全。

#2


Others have given accurate and detailed answers, but here I will try to explain in simple language.

其他人给出了准确而详细的答案,但在这里我将尝试用简单的语言解释。

When you write worksheet["A2"] you really are calling a member function of worksheet

当你编写工作表[“A2”]时,你真的在​​调用工作表的成员函数

worksheet has a member function named [] that accepts a string and returns an object

工作表有一个名为[]的成员函数,它接受一个字符串并返回一个对象

The signature of the member function [] looks like object this[string id]

成员函数[]的签名看起来像对象[string id]

So the function worksheet["A2"] returns something that is an object. It could be an int or a string or many other things. All the compiler knows is that it will be an object.

因此函数工作表[“A2”]返回一个对象。它可以是int或字符串或许多其他东西。所有编译器都知道它将是一个对象。

In the example, you have it returning a Func<object>. This is fine, because Func<object> is an object. However, you then pass the result of that function in as a parameter to another function.

在该示例中,您将返回一个Func 。这很好,因为Func 是一个对象。但是,然后将该函数的结果作为参数传递给另一个函数。

The problem here is that the compiler only knows that worksheet["A2"] returns an object. That is as specific as the compiler can be. So the compiler sees that worksheet["A2"] is an object, and you are trying to pass the object to a function that does not accept object as a parameter.

这里的问题是编译器只知道工作表[“A2”]返回一个对象。这与编译器一样具体。因此编译器看到工作表[“A2”]是一个对象,并且您试图将该对象传递给不接受对象作为参数的函数。

So here you have to tell the compiler "hey dummy, that's a Func<object>" by casting the returned object to the correct type.

所以在这里你必须通过将返回的对象强制转换为正确的类型来告诉编译器“hey dummy,这是一个Func ”。

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

can be re-written as

可以重写为

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

Now the compiler knows that, even though the [] function returns an object, it can treat it like a Func<object>.

现在编译器知道,即使[]函数返回一个对象,它也可以将它视为Func

side note: You're probably doing too much on one line. That may be hard for people to read in the future.

旁注:你可能在一条线上做得太多了。人们今后可能难以阅读。

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

为什么被调用的方法“看到”参数与GetType()返回的类型不同?

The compiler only knows that worksheet[] returns an object. The compiler can not call GetType() on it at compile time.

编译器只知道worksheet []返回一个对象。编译器无法在编译时调用GetType()。

What good is the GetType() method?

GetType()方法有什么用?

There are quite a few uses and abuses of the GetType() method, but that is an entirely different discussion. ;)

GetType()方法有很多用途和滥用,但这是一个完全不同的讨论。 ;)

In summary, the compiler does not assume anything about types. This is a good thing because you get a compile time error when you try to fit this square peg into a round hole. If the compiler did not complain, this error would surface at run-time, which means you would probably need a unit test to detect the problem.

总之,编译器不会假设有关类型的任何内容。这是一件好事,因为当您尝试将此方形钉插入圆孔时,会出现编译时错误。如果编译器没有抱怨,则此错误将在运行时出现,这意味着您可能需要单元测试来检测问题。

You can get around this problem by telling the compiler "I know for a fact that this thing is a round peg, trust me." and then it will compile. If you lie to the compiler, you will get a run-time error when that code is executed.

你可以通过告诉编译器“我知道这个东西是一个圆形挂钩,相信我”来解决这个问题。然后它将编译。如果您对编译器撒谎,则在执行该代码时会出现运行时错误。

This is called "static typing". The opposing philosophy is called "dynamic typing" where type checks are done at run-time. Static vs dynamic is a lengthy debate and you should probably research it on your own if you're interested.

这称为“静态类型”。反对的哲学被称为“动态类型”,其中类型检查在运行时完成。静态与动态是一个冗长的争论,如果你感兴趣,你应该自己研究它。

#3


VS claims that both args in the method call above are of type object whereas the method accepts only Func. But the value of both worksheet elements is of type Func

VS声称上面的方法调用中的两个args都是object类型,而该方法只接受Func。但是两个工作表元素的值都是Func类型

Yes, but the declared type is object. The compiler can't know that the actual runtime type will be Func<object>, so an explicit cast is necessary.

是的,但声明的类型是对象。编译器无法知道实际的运行时类型将是Func ,因此需要进行显式转换。