我想知道为什么第一次调用Bar(ref object)
不起作用而第二次调用不起作用。考虑到我以任意方式传递object
类型,和以匿名类型传递给Foo(object)
,这看起来很傻。为什么ref
与内存位置有关的内容会影响对Bar()
的调用?
请考虑以下代码段:
static void Foo(object obj)
{ }
static void Bar(ref object obj)
{ }
static void Main()
{
// Compiles
var a = new { };
Foo(a);
// Does not compile
var b = new { };
Bar(ref b);
// Compiles
object c = new { };
Bar(ref c);
}
我在下面的答案中看到了如何编译代码的建议,但这不是我所追求的。我想特别知道为什么将ref
参数设置为阻止编译时,将匿名类型传递给Foo()
工作正常。
答案 0 :(得分:7)
主要原因有点隐藏:发生这种情况是因为传入的参数必须是 exact 与参数中定义的类型相同的类型。
这是(含糊不清的?)在规范部分$ 10.6.1.2中说明:
当形式参数是引用参数时,方法调用中的相应参数必须是 由关键字ref 后跟变量引用(§5.3.3)组成,其类型与形式参数相同。
出于同样的原因,将子类传递给使用引用参数的方法不起作用。这在Jeff Mercado的回答中有所描述。
在您的第一个示例中,您不使用ref
因此多态性有效(匿名类型是object
的子类型),在最后一个示例中,您将其声明为object
,这意味着您使用与参考参数完全相同的类型。
答案 1 :(得分:5)
为什么要这样?变量b
未被声明为方法所期望的object
。
考虑这个例子:
string s;
GetValue(ref s); // no...
void GetValue(ref object x)
{
x = 123;
}
答案 2 :(得分:0)
通过不允许带参数的参数类型的函数,编译器实际上阻止了对类型安全的妥协。在以下场景中也会发生同样的情况
private static void MyMethod(out object MyPara)
{
MyPara = new String('x', 10);
}
MyClass obj = new MyClass();
MyMethod(out obj); //compile time error
编译器实际上是通过不允许这个场景进行编译来保持obj的内存位置安全。如果允许这样做,应用程序的安全性很容易受到损害
答案 3 :(得分:-1)
类型推断很聪明,但它无法读懂你的想法。因此,仅仅声明var b = new { };
根本不足以使编译器理解,您想要的东西,可以作为对象重新传递。
var b = new Object ();
Bar (ref b);
将会工作。