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

属性和参考参数,为什么不加糖?

  •  69
  • BCS  · 技术社区  · 16 年前

    我在C中工作时遇到了这个错误消息#

    属性或索引器不能作为out或ref参数传递

    我知道是什么导致了这种情况,并快速解决了创建一个正确类型的局部变量的问题,用它调用函数作为 out / ref 参数,然后将其分配回属性:

    RefFn(ref obj.prop);
    

    变成

    {
        var t = obj.prop;
        RefFn(ref t);
        obj.prop = t;
    }
    

    显然,如果属性不支持当前上下文中的get和set,则此操作将失败。

    为什么不为我这么做?


    我能想到的唯一可能导致问题的情况是:

    • 螺纹加工
    • 例外情况

    对于线程来说,转换会影响写入的时间(在函数调用之后,而不是在函数调用中),但是我更怀疑任何依赖它的代码在中断时都不会得到同情。

    对于异常,问题是:如果函数分配给几个函数中的一个,会发生什么? 裁判 参数比抛出?任何微不足道的解决方案都会导致在某些参数应该是而某些参数不应该是时分配给所有或没有参数。我也不认为这会被支持使用这种语言。


    注意:我了解生成此错误消息的机制。我正在寻找的是为什么C不能自动实现这些琐碎的变通方法的基本原理。

    9 回复  |  直到 14 年前
        1
  •  11
  •   Marc Gravell    16 年前

    仅供参考,C 4.0 有什么 喜欢 这是一种优势,但只有在调用互操作方法时才如此——部分原因是 ref 在这种情况下。我没有做过太多的测试(在CTP中);我们得看看结果如何……

        2
  •  32
  •   David Morton    16 年前

    因为你通过了 结果 索引器,这实际上是方法调用的结果。不能保证索引器属性也有一个setter,如果开发者认为他的属性将在不调用setter的情况下设置,那么通过ref传递该属性将导致开发者的错误安全。

    在更技术的层面上,ref和out传递传递传递给它们的对象的内存地址,并且要设置一个属性,必须调用setter,所以不能保证属性实际上会被更改,特别是当属性类型是不可变的时。裁判和出局不仅仅是 设置 返回方法时的值,它们将实际内存引用传递给对象本身。

        3
  •  17
  •   user7116    16 年前

    属性只不过是Java风格GETX/SETX方法上的语法糖。对于方法上的“ref”来说,它没有多大意义。在您的实例中,这是有意义的,因为您的属性只是存根字段。属性不必只是存根,因此框架不允许对属性使用“ref”。

    编辑 :好吧,简单的答案是,仅仅一个属性getter或setter可以包含远远超过字段读/写的事实,就不希望允许您提议的糖的种类,更不用说可能是意外的。这并不是说我以前不需要这个功能,只是说我理解为什么他们不想提供它。

        4
  •  9
  •   Brian Rasmussen    16 年前

    您可以使用字段 ref / out ,但不是属性。原因是属性实际上只是特殊方法的语法捷径。编译器实际上将get/set属性转换为相应的 get_X set_X 方法,因为clr不立即支持属性。

        5
  •  6
  •   Mark Rendle    16 年前

    这不是线程安全的;如果两个线程同时创建自己的属性值副本并将它们作为引用参数传递给函数,那么只有一个线程返回到属性中。

    class Program
    {
      static int PropertyX { get; set; }
    
      static void Main()
      {
        PropertyX = 0;
    
        // Sugared from: 
        // WaitCallback w = (o) => WaitAndIncrement(500, ref PropertyX);
        WaitCallback w = (o) => {
          int x1 = PropertyX;
          WaitAndIncrement(500, ref x1);
          PropertyX = x1;
        };
        // end sugar
    
        ThreadPool.QueueUserWorkItem(w);
    
        // Sugared from: 
        // WaitAndIncrement(1000, ref PropertyX);
        int x2 = PropertyX;      
        WaitAndIncrement(1000, ref x2);
        PropertyX = x2;
        // end sugar
    
        Console.WriteLine(PropertyX);
      }
    
      static void WaitAndIncrement(int wait, ref int i)
      {
        Thread.Sleep(wait);
        i++;
      }
    }
    

    propertyx最终为1,而字段或局部变量为2。

    这个代码示例还强调了匿名方法在要求编译器做一些有说服力的事情时所带来的困难。

        6
  •  4
  •   Andrew Hare    16 年前

    原因是C不支持接受引用传递的参数的“parameterful”属性。值得注意的是,clr确实支持这种功能,但c不支持。

        7
  •  4
  •   Peter Mortensen icecrime    14 年前

    当预先传递ref/out时,意味着您传递的是存储在堆中的引用类型。

    属性是包装方法,而不是变量。

        8
  •  1
  •   BC.    16 年前

    如果您问编译器为什么不替换属性getter返回的字段,这是因为getter可以返回常量、只读或文本或其他不应重新初始化或重写的内容。

        9
  •  0
  •   regex    16 年前

    这个网站似乎有你的工作。但是我还没有测试过,所以我不能保证它能正常工作。该示例似乎使用反射来访问属性的get和set函数。这可能不是推荐的方法,但它可能会满足您的要求。

    http://www.codeproject.com/KB/cs/Passing_Properties_byref.aspx

    推荐文章