【问题标题】:C# struct by-refC# 结构按引用
【发布时间】:2012-02-05 13:02:57
【问题描述】:

在 C# 中有什么方法可以做到这一点:

map.player.x = 5;

在保持Point 类型的player(或静默转换为1)的同时,仍然能够在执行分配时检查值的正确性?

为了更清楚:

  • Point 是 C#/.net 标准库定义的结构体,按值传递。
  • 创建一个包装类并将Point 的所有方法实现为对Point 的调用既冗长又乏味。
  • 拥有一个只对Point 进行隐式覆盖的包装类将不允许上述情况。它必须写成(Point)(map.player).x,这很笨拙。

【问题讨论】:

  • 应该是X(不是x)吗?标准Point有X和Y,c#对大小写很挑剔……?
  • 另外,玩家是属性还是字段?大概是这里的一个领域? (否则它不会编译,IIRC)
  • @MarcGravell 是的,它应该是 X。如果它是一个属性或一个字段,我正在辩论。我想获得两者的优势。
  • 您的Point 真的与.NET 库中的“标准”Point 有任何关系吗?可变结构是邪恶的。除非您有充分的理由,否则请避免使用它们。
  • @Jason 只是比自己实现所有的操作符更方便。

标签: c# .net struct ref


【解决方案1】:

有些人会建议使用类类型来保存 X 和 Y 值。我对这种方法持怀疑态度,并建议在许多情况下,通过将player 公开为字段所获得的语义会更清晰(尽管我不清楚为什么map 有一个名为player 的成员。如果@ 987654324@ 是对MapType 的引用,MapType 的实例有一个结构类型为player 的字段,其中有一个整数类型的字段x,很明显,对map.player.x 的更改将影响一个实例MapType。此外,说map1.player = map2.player; 会将字段从map2.player 复制到map1.player。相比之下,如果player 属于一个类类型而一个属于map1.player = map2.player; map1.player.x = 5;,这将影响map1map2.

是使用可变结构还是使用可变类的问题非常简单,但是“如果它是可变的,就让它成为一个类”的概念是完全错误的。简单地问自己,给定:

事物1 =事物2; 东西1.x = 5;

您是否希望第二条语句影响thing2.x 的值?如果是,请使用类。如果不是,请使用结构。

顺便说一句,如果您不希望地图类型将 player 作为字段公开,则要考虑的另一种模式是让它公开一个 ActOnPlayer 方法:

公共委托 ActionByRef(ref T p); 公共委托 ActionByRef(ref T1 p1, ref T2 p2); 公共无效ActOnPlayer(ActionByRef proc;) { 过程(参考 _player); } public void ActOnPlayer(ActionByRef {it.x = theParam;}, someIntVariable);

请注意,后一种方法看起来有点像使用闭包,但与使用闭包不同的是,它不会生成任何新的临时堆对象,因此不会对垃圾收集器造成任何压力。

【讨论】:

    【解决方案2】:

    1

    同时分配两个坐标怎么样?

    map.player = new Point(5, 7);
    

    现在您可以在 player 属性中包含验证逻辑。


    2

    你真的需要实现System.Drawing.Point 的所有东西吗?只用你真正需要的东西来实现你自己的版本应该不会太难。 Point的逻辑不多。

    【讨论】:

      【解决方案3】:

      如果我理解正确,您似乎希望通过定义类型转换来获得一些灵活性。那不会走得很远。

      避免可变结构(值类型)。 struct Point 是旧 Win32 API 的不幸遗留物。

      所以瞄准map.player = new Point(5, map.player.y);

      【讨论】:

      • @baruch: Everything :) 说真的,搜索“evil mutable struct”,你会发现很多意见,支持和反对。大多数情况下,您最终会遇到这种尴尬的情况,以及在其他情况下的意外行为。
      【解决方案4】:

      没有。 player 是一个变量,在这种情况下,您没有机会在分配期间验证更改,或者player 是一个属性,其中如果表达式 map.player 被归类为 并且您不能设置 x 部分(因为它是无用的)。

      我建议你创建一个方法,这样你就可以调用:

      map.SetPlayerX(5);
      

      ... 或者您更改 x 值的一部分,该操作由 Player 类拥有。这可能是一种更面向对象的方法 - 通常如果您发现自己想做这样的事情,那么值得看看设计和职责。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-05-12
        • 2011-02-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多