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

发布于 2024-08-12 10:50:34 字数 1544 浏览 5 评论 0原文

好的,我将从 .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...
}

这行代码直接来自 System.Web.Security.SqlMembershipProvider.UpdateUser (System.Web.dll v2.0.50727) .NET框架。

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

CheckParameter 代码的定义是:

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

它所做的一切都是有意义的 - 在纸上......所以我为我想使用类似的东西的地方创建了一个快速的小原型:

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.
    }
}

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

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

很公平...但是为什么我的代码不允许我执行 .NET Framework 代码库中的操作?这是 .NET Reflector 解释 DLL 的方式错误还是我解释其代码的方式错误?

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

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.

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.

The definition of the CheckParameter code is:

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

煮酒 2024-08-19 10:50:34

我认为这是来自 Reflector 的一些糟糕的解释。实际上,如果您像这样编写代码:

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

并在发布模式下编译它,您将在 Reflector 中看到这一点:

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

请记住,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)

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

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

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:

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:

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.

暖伴 2024-08-19 10:50:34

这是一个反射器错误。它并不是真正通过引用传递属性。

这里有一些可以重现它的 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 显示了 Foo 的代码:

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

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

在您的原始示例中,它更没有意义,因为 UserName 是只读属性!

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

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

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:

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.

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

蔚蓝源自深海 2024-08-19 10:50:34

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

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

它不是最优雅的解决方案,但它应该为您指明正确的方向。正如 Yuriy 在上面的评论中所说,这可能与您没有明确声明该属性的 get 和 set 有关。

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.

找回味觉 2024-08-19 10:50:34

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文