当.NET反射器显示它在.NET Framework中完成时,为什么我不能将属性或索引器作为ref参数传递?

时间:2021-11-19 02:31:49

Okay, I will cut and paste from .NET reflector to demonstrate what I'm trying to do:

好的,我将从.NET反射器剪切和粘贴以演示我正在尝试做的事情:

public override void UpdateUser(MembershipUser user)
{
    //A bunch of irrelevant code...

    SecUtility.CheckParameter(ref user.UserName, true, true, true, 0x100, "UserName");

    //More irrelevant code...
}

This line of code comes right out of System.Web.Security.SqlMembershipProvider.UpdateUser (System.Web.dll v2.0.50727) in the .NET Framework.

这行代码来自.NET Framework中的System.Web.Security.SqlMembershipProvider.UpdateUser(System.Web.dll v2.0.50727)。

The SecUtility.CheckParameter requires a reference value as the first parameter, to which they're passing a property of the user passed in as the argument.

SecUtility.CheckParameter需要一个引用值作为第一个参数,它们将传入的用户属性作为参数传递给它。

The definition of the CheckParameter code is:

CheckParameter代码的定义是:

internal static void CheckParameter(ref string param, bool checkForNull, bool checkIfEmpty, bool checkForCommas, int maxSize, string paramName)
{
    //Code omitted for brevity
}

Everything it's doing makes sense - on paper... so I knock up a quick little prototype for somewhere I'd like to use something similar:

它所做的一切都很有意义 - 在纸面上...所以我在某个地方敲了一个快速的小原型,我想用类似的东西:

public class DummyClass
{
    public string ClassName{ get; set; }
}

public class Program
{
    private static DoSomething(ref string value)
    {
        //Do something with the value passed in
    }

    public static Main(string[] args)
    {
        DummyClass x = new DummyClass() { ClassName = "Hello World" };

        DoSomething(ref x.ClassName); //This line has a red squiggly underline 
                                      //under x.ClassName indicating the 
                                      //error provided below.
    }
}

This code won't compile - the error shows as:

此代码将无法编译 - 错误显示为:

"A property or indexer may not be passed as an out or ref parameter"

Fair enough... but why won't my code allow me to do something that appears to be in the .NET Framework code base? Is this an error with the way .NET Reflector is interpreting the DLL or is this an error with the way I'm interpreting their code?

很公平......但为什么我的代码不允许我做一些似乎在.NET Framework代码库中的东西?这是.NET Reflector解释DLL的方式的错误,还是我解释其代码的错误?

4 个解决方案

#1


15  

I think it is some bad interpretation from Reflector. Actually if you write your code like this:

我认为这是Reflector的一些不好的解释。实际上,如果你编写这样的代码:

static void Main(string[] args)
{
    DummyClass x = new DummyClass();
    string username = x.ClassName;
    DoSomething(ref username);
}

and compile it in Release mode you will see this in Reflector:

并在Release模式下编译它,您将在Reflector中看到它:

static void Main(string[] args)
{
    DummyClass x = new DummyClass();
    DoSomething(ref x.ClassName);
}

Remember that the C# compiler is not producing C# code but IL so what you see in Reflector is not always the reality. So to clearly understand what is going on under the hood you may look at the real code produced by the compiler:

请记住,C#编译器不会生成C#代码,而是IL,因此您在Reflector中看到的并不总是现实。因此,为了清楚地了解底层的内容,您可以查看编译器生成的实际代码:

L_000f: callvirt instance string System.Web.Security.MembershipUser::get_UserName()
L_0014: stloc.0 
L_0015: ldloca.s str
L_0017: ldc.i4.1 
L_0018: ldc.i4.1 
L_0019: ldc.i4.1 
L_001a: ldc.i4 0x100
L_001f: ldstr "UserName"
L_0024: call void System.Web.Util.SecUtility::CheckParameter(string&, bool, bool, bool, int32, string)

It is clear that a local variable is used.

很明显,使用了局部变量。

#2


6  

It's a reflector bug. It isn't really passing the property by reference.

这是一个反射器错误。它并没有真正通过参考传递财产。

Here's some C# code which will reproduce it.

这里有一些C#代码可以重现它。

using System;

class Person
{
    public string Name { get; set; }
}

class Test
{
    static void Main(){} // Just make it easier to compile

    static void Foo(Person p)
    {
        string tmp = p.Name;
        Bar(ref tmp);
    }

    static void Bar(ref string x)
    {
    }
}

Reflector shows this code for Foo:

Reflector为Foo显示以下代码:

private static void Foo(Person p)
{
    Bar(ref p.Name);
}

Not only is this invalid C#, but it's misleading - it would suggest that changes made to x within Bar would somehow modify p.Name - where that's not the case when you look at the original C# code.

这不仅是无效的C#,而且是误导性的 - 它会暗示对Bar中的x所做的更改会以某种方式修改p.Name - 当你查看原始的C#代码时,情况并非如此。

In your original sample, it makes even less sense as UserName is a read-only property!

在您的原始示例中,由于UserName是只读属性,因此更不合理!

#3


1  

Try setting the value of the property to a variable before passing it to the function.

在将属性传递给函数之前,请尝试将该属性的值设置为变量。

string myClassName = x.ClassName
DoSomething(ref myClassName);

Its not the most elegant solution, but it should point you in the right direction. As Yuriy said in his comment above, its probably something to do with the fact that you aren't explicitly declaring a get and set for the property.

它不是最优雅的解决方案,但它应该指向正确的方向。正如Yuriy在上面的评论中所说,它可能与你没有明确宣布物业的获取和设定这一事实有关。

#4


0  

When you pass a variable as a ref or out, the call actually points to the memory where it is originally located. So if you are allowed to pass the property as a reference, it means you are making the class member inconsistent. This is the reason behind this problem.

将变量作为ref或out传递时,该调用实际上指向它最初所在的内存。因此,如果允许您将属性作为引用传递,则意味着您使类成员不一致。这就是这个问题背后的原因。

#1


15  

I think it is some bad interpretation from Reflector. Actually if you write your code like this:

我认为这是Reflector的一些不好的解释。实际上,如果你编写这样的代码:

static void Main(string[] args)
{
    DummyClass x = new DummyClass();
    string username = x.ClassName;
    DoSomething(ref username);
}

and compile it in Release mode you will see this in Reflector:

并在Release模式下编译它,您将在Reflector中看到它:

static void Main(string[] args)
{
    DummyClass x = new DummyClass();
    DoSomething(ref x.ClassName);
}

Remember that the C# compiler is not producing C# code but IL so what you see in Reflector is not always the reality. So to clearly understand what is going on under the hood you may look at the real code produced by the compiler:

请记住,C#编译器不会生成C#代码,而是IL,因此您在Reflector中看到的并不总是现实。因此,为了清楚地了解底层的内容,您可以查看编译器生成的实际代码:

L_000f: callvirt instance string System.Web.Security.MembershipUser::get_UserName()
L_0014: stloc.0 
L_0015: ldloca.s str
L_0017: ldc.i4.1 
L_0018: ldc.i4.1 
L_0019: ldc.i4.1 
L_001a: ldc.i4 0x100
L_001f: ldstr "UserName"
L_0024: call void System.Web.Util.SecUtility::CheckParameter(string&, bool, bool, bool, int32, string)

It is clear that a local variable is used.

很明显,使用了局部变量。

#2


6  

It's a reflector bug. It isn't really passing the property by reference.

这是一个反射器错误。它并没有真正通过参考传递财产。

Here's some C# code which will reproduce it.

这里有一些C#代码可以重现它。

using System;

class Person
{
    public string Name { get; set; }
}

class Test
{
    static void Main(){} // Just make it easier to compile

    static void Foo(Person p)
    {
        string tmp = p.Name;
        Bar(ref tmp);
    }

    static void Bar(ref string x)
    {
    }
}

Reflector shows this code for Foo:

Reflector为Foo显示以下代码:

private static void Foo(Person p)
{
    Bar(ref p.Name);
}

Not only is this invalid C#, but it's misleading - it would suggest that changes made to x within Bar would somehow modify p.Name - where that's not the case when you look at the original C# code.

这不仅是无效的C#,而且是误导性的 - 它会暗示对Bar中的x所做的更改会以某种方式修改p.Name - 当你查看原始的C#代码时,情况并非如此。

In your original sample, it makes even less sense as UserName is a read-only property!

在您的原始示例中,由于UserName是只读属性,因此更不合理!

#3


1  

Try setting the value of the property to a variable before passing it to the function.

在将属性传递给函数之前,请尝试将该属性的值设置为变量。

string myClassName = x.ClassName
DoSomething(ref myClassName);

Its not the most elegant solution, but it should point you in the right direction. As Yuriy said in his comment above, its probably something to do with the fact that you aren't explicitly declaring a get and set for the property.

它不是最优雅的解决方案,但它应该指向正确的方向。正如Yuriy在上面的评论中所说,它可能与你没有明确宣布物业的获取和设定这一事实有关。

#4


0  

When you pass a variable as a ref or out, the call actually points to the memory where it is originally located. So if you are allowed to pass the property as a reference, it means you are making the class member inconsistent. This is the reason behind this problem.

将变量作为ref或out传递时,该调用实际上指向它最初所在的内存。因此,如果允许您将属性作为引用传递,则意味着您使类成员不一致。这就是这个问题背后的原因。