C# 为什么可以';当.NET reflector显示属性或索引器';是在.NET框架中完成的吗?

C# 为什么可以';当.NET reflector显示属性或索引器';是在.NET框架中完成的吗?,c#,.net,.net-reflector,C#,.net,.net Reflector,好的,我将从.NET reflector中剪切并粘贴以演示我正在尝试执行的操作: public override void UpdateUser(MembershipUser user) { //A bunch of irrelevant code... SecUtility.CheckParameter(ref user.UserName, true, true, true, 0x100, "UserName"); //More irrelevant code...

好的,我将从.NET reflector中剪切并粘贴以演示我正在尝试执行的操作:

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

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

    //More irrelevant code...
}
这行代码直接来自.NET Framework中的System.Web.Security.SqlMembershipProvider.UpdateUser(System.Web.dll v2.0.50727)

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"

很公平。。。但是为什么我的代码不允许我做一些看起来在.NETFramework代码库中的事情呢?这是.NET Reflector解释DLL时的错误,还是我解释其代码时的错误?

我认为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)

显然使用了局部变量。

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

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

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

这是一个反射程序错误。它实际上不是通过引用传递属性

这里有一些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)
    {
    }
}
反射器为
Foo
显示此代码:

private static void Foo(Person p)
{
    Bar(ref p.Name);
}
这不仅是无效的C#,而且是误导性的-它表明对
Bar
中的
x
所做的更改会以某种方式修改
p.Name
-当您查看原始C#代码时,情况并非如此


在您的原始示例中,由于
UserName
是只读属性,因此它的意义就更小了

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

您正在使用自动属性。当它被编译时,它被转换成两个函数。因此,框架无法将对两个函数的引用传递到其他函数中。@Yuriy-这是可以理解的。然而,在引起我注意到这个问题的代码中,我使用的是框架中引用的同一MembershipUser类,方式完全相同-为什么可以在框架内完成而不能在框架外完成?当你需要他时@JonSkeet在哪里…@Ben:我来了,我来了。。。再给我几分钟:)看来是反射器的问题。在IL代码中,局部变量被创建到堆栈上并传递给CheckParameter()method@Darin-但这在语义上不是不同吗?username现在不是x.ClassName的副本,我们传递的是对字符串“username”的引用,而不是对字符串“x.ClassName”的引用…@Darin-发布模式代码摘录现在让我抓狂。。。它是如何将代码更改为我自己无法编写的代码,因为编译器不允许这样做的?本:是的,它在语义上是不同的。这就是为什么Darin说反射器的解释不好。Reflector应该显示分配给本地用户的user.UserName,以及通过ref传递给CheckParameter的本地用户。调试或发布模式并不影响这一点:Darin的源代码和“Reflector”代码所显示的是Reflector反编译是错误的——它在语义上与他的源代码不同(正如您所观察到的,这是非法的)。@Kyle-我已经将其视为语义不同。因为我是在引用x.ClassName。myClassName现在将是字符串的副本,我将传递对副本的引用。但是现在@Darin Dimitrov让我想知道发布模式的编译…我的原始样本是直接从reflector剪切粘贴的,这就是为什么我说“从reflector”时让我挠头的原因。NET reflector对System.Web.dll(v2.0.50727)的解释-我知道你对准确的术语很挑剔:P@BenAlabaster:我的“反射器显示此代码…”位也是从反射器上剪下来粘贴的:)然后再问你一个问题:我不知道红门的反射器在封面下是如何工作的,我也不擅长IL。RedGates的reflector是建立在.NET反射之上的吗?因此,这是.NET反射的一个限制还是一个只影响reflector工具的问题?@Ben:反射API不进行反编译-这完全取决于reflector。我不知道Reflector是仅仅使用反射还是(更可能是IMO)读取文件并直接分析它们。