简体   繁体   English

C#struct by-ref

[英]C# struct by-ref

Is there any way in C# to be able to do this: C#中有什么方法可以做到这一点:

map.player.x = 5;

while keeping player of type Point (or silently convertible to one) and still be able to check the value for correctness when doing the assignment? 同时保持Point类型(或无声转换为一个)的player ,并且在进行分配时仍然能够检查该值的正确性?

To be clearer: 要更清楚:

  • Point is a struct defined by the C#/.net standard libraries and is passed by value. Point是C#/。net标准库定义的结构,并按值传递。
  • Making a wrapper class and implementing all of Point 's methods as call-throughs to Point is long and tedious. 制作一个包装类和实现所有的Point的方法,例如呼叫中指向Point是漫长而乏味。
  • Having a wrapper class with nothing but an implicit coversion to/from Point will not allow the above. 只有一个包装类,而对Point的隐式覆盖只允许上述内容。 It would have to be written as (Point)(map.player).x , which is clumsy. 它必须写为(Point)(map.player).x ,很笨拙。

If I understand you right, you seem to want to get some flexibility by defining type-conversions. 如果我理解正确,那么您似乎希望通过定义类型转换来获得一定的灵活性。 That won't go very far. 那不会太远。

Avoid mutable structs (value types). 避免使用可变结构(值类型)。 struct Point is an unfortunate leftover from the old Win32 API. struct Point是旧Win32 API的一个不幸残left。

So aim for map.player = new Point(5, map.player.y); 因此,瞄准map.player = new Point(5, map.player.y);

No. Either player is a variable , in which case you don't get any chance to verify the change during the assignment, or player is a property , in which case the expression map.player is categorized as a value and you're not allowed to set the x part (as it would be usless). 号无论player是一个变量 ,在这种情况下,你没有得到任何机会,以验证分配过程中的变化,或player是一个属性 ,在这种情况下,表达map.player被归类为一个 ,你不允许设置x部分(这将是无用的)。

I would suggest you create a method, so you can call: 我建议您创建一个方法,以便可以调用:

map.SetPlayerX(5);

... or you make changing the x value part of a larger operation which is owned by the Player class. ...或者您可以更改Player类拥有的较大操作的x值部分。 That's likely to be a more OO approach - usually if you find yourself wanting to do something like this, it's worth taking a look at the design and responsibilities. 这很可能是一种面向对象的方法- 通常,如果您发现自己想做这样的事情,那么值得研究一下设计和职责。

1 1个

What about assigning both coordinates at the same time? 如何同时分配两个坐标呢?

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

Now you can have the validation logic inside of the player property. 现在,您可以在播放器属性中包含验证逻辑。


2 2

Do you really need to implement all the stuff of System.Drawing.Point ? 您真的需要实现System.Drawing.Point所有功能吗? It should not be all too difficult to implement your own version with only the things you really need. 仅使用您真正需要的东西来实现自己的版本并不难。 There is not much logic in Point . Point没有太多逻辑。

Some people would suggest using a class type to hold the X and Y values. 有人建议使用类类型来保存X和Y值。 I am leery of that approach, and would suggest that in many cases the semantics obtained by exposing player as a field would be much cleaner (though I'm unclear why map has a member called player . If an map is reference to MapType , and instance of MapType has a field of struct type player , with a field x of type integer, it is clear that a change to map.player.x will affect one instance of MapType . Also, saying map1.player = map2.player; will copy the fields from map2.player to map1.player . By contrast, if player were of a class type and one did map1.player = map2.player; map1.player.x = 5; , that would affect both map1 and map2 . 我对这种方法持怀疑态度,并建议在许多情况下,将player公开为字段所获得的语义会更加简洁(尽管我不清楚为什么map有一个名为player的成员。如果map引用了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

The question of whether to use a mutable struct versus a mutable class is pretty straightforward, but the notion of "If it's mutable make it a class" is just plain wrong. 关于使用可变结构还是可变类的问题很简单,但是“如果可变则使它成为一个类”的概念是完全错误的。 Simply ask yourself, given: 只需问问自己,给出:

thing1 = thing2;
  thing1.x = 5;

would you want the second statement to affect the value of thing2.x ? 您是否要第二条语句影响thing2.x的值? If yes, use a class. 如果是,请使用课程。 If no, use a struct. 如果否,请使用结构。

BTW, abother pattern to consider if you don't want your map type to expose player as a field would be to have it expose an ActOnPlayer method: 顺便说一句,如果您不希望地图类型将player为字段,则需要考虑的另一种模式是使其显示ActOnPlayer方法:

public delegate ActionByRef<T>(ref T p);
  public delegate ActionByRef<T1,T2>(ref T1 p1, ref T2 p2);

  public void ActOnPlayer(ActionByRef<playerType> proc;)
  {
    proc(ref _player);
  }
  public void ActOnPlayer<T>(ActionByRef<playerType,T> proc, ref T param;)
  {
    proc(ref _player, ref param);
  }
... sample usage:
  map.ActOnPlayer((ref playerType it, ref int theParam) ->
    {it.x = theParam;}, someIntVariable);

Note that the latter approach would look something like using a closure, but unlike using a closure it would not generate any new temporary heap objects, and would thus not create any pressure on the garbage collector. 请注意,后一种方法看起来类似于使用闭包,但是与使用闭包不同,它不会生成任何新的临时堆对象,因此不会对垃圾收集器造成任何压力。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM