代码之家  ›  专栏  ›  技术社区  ›  BenAlabaster

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

  •  12
  • BenAlabaster  · 技术社区  · 16 年前

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

    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的方式的错误,还是我解释其代码的方式的错误?

    4 回复  |  直到 16 年前
        1
  •  15
  •   Darin Dimitrov    16 年前

    我认为这是反射器的一些错误解释。实际上,如果您这样编写代码:

    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)
    

        2
  •  6
  •   Jon Skeet    16 年前

    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#,而且是误导性的——它表明对 x Bar 会以某种方式改变 p.Name

    在您的原始示例中,它作为 UserName 是只读属性!

        3
  •  1
  •   Kyle Trauberman pestades    16 年前

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

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

        4
  •  0
  •   Tamilmaran    14 年前

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

    推荐文章