我可以将匿名对象传递给需要类型对象引用参数的方法吗?

Can I pass an anonymous object into a method that expects a reference parameter of type object?

我想知道为什么第一次调用 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);
}

我在下面的答案中看到了关于如何编译代码的建议,但这不是我想要的。我想具体知道为什么在将匿名类型传递给 Foo() 时将其设为 ref 参数会阻止编译工作正常。

为什么要这样做?变量 b 未按方法预期的那样声明为 object

考虑这个例子:

string s;
GetValue(ref s); // no...

void GetValue(ref object x)
{
    x = 123;
}

类型推断很聪明,但它无法读懂你的心思。所以仅仅声明 var b = new { }; 并不足以让编译器理解你想要的东西,可以作为对象引用传递。

var b = new Object ();
Bar (ref b);

当然可以。

主要原因有点隐蔽:发生这种情况是因为您传入的参数必须与参数中定义的类型完全相同。

这在规范部分 $10.6.1.2 中有(含糊不清?)说明:

When a formal parameter is a reference parameter, the corresponding argument in a method invocation must consist of the keyword ref followed by a variable-reference (§5.3.3) of the same type as the formal parameter.

出于同样的原因,将子类传递给使用引用参数的方法是行不通的。 Jeff Mercado 的回答中对此进行了描述。

在你的第一个例子中你没有使用 ref 所以多态性有效(匿名类型是 object 的子类型)并且在最后一个例子中你将它声明为 object这意味着您使用与参考参数完全相同的类型。

通过不允许带有 ref 和参数类型的函数,编译器实际上是在防止与类型安全妥协。同样的情况也发生在下面的场景中

    private static void MyMethod(out object MyPara)
    {
        MyPara = new String('x', 10);
    }

    MyClass obj = new MyClass();
    MyMethod(out obj); //compile time error

编译器实际上是通过不允许这种情况进行编译来保证 obj 的内存位置安全。如果允许这样做,应用程序的安全性很容易受到威胁