为什么我的C#struct在传入方法时被重置

时间:2013-02-18 15:30:53

标签: c# struct parameter-passing reset

我正在制作一个简单的文字游戏。我的Character结构体不断重置Can值。我做错了什么,我该如何解决?这是代码:

namespace MyNamespace
{
   struct Character
   {
      public float Can;
      //...
   }

   class MainClass
   {
      public static void Move (Character a)
      {
         bool cal = true;

         while (cal) 
         {
            Thread.Sleep(500);

            if(a.Can <= 100)
            {
               a.Can += 1;
            }
            else
            {
               cal = false;
            }
         }
     }
  }

  //...
}

6 个答案:

答案 0 :(得分:2)

struct值类型。将其传递给方法或将其分配给另一个变量时,数据被复制。然后,您将操作一份副本。

考虑您的方法调用 Dinlen (oyuncu); 。它复制了Karakter oyuncu,然后更改了副本的字段Can

请考虑使用引用类型(class)。如果您使用struct,请考虑将其设为不可变类型。阅读帖子 Why are mutable structs evil?

答案 1 :(得分:0)

当您将struct instance传递给方法时,会创建一个struct的副本(它按值传递)。对struct inside方法的任何更改都不会影响您传递的原始结构。

解决方案?使用class而不是struct。通过引用传递的类实例。那么你可以通过引用传递结构,但为什么你会尝试使用像类这样的结构?改为使用类。

class Karakter
{
    public string Isim { get; set; }
    public float Can { get; set; }
    public int Seviye { get; set; }
    public int Exp { get; set; }
    public float Guc { get; set; }
    public string Irk { get; set; }
    public int vExp { get; set; }

    public override string ToString()
    {
        return String.Format("Adınız:{0}\nIrkınız:{1}\nCan:{2}\nGuc:{3}", 
                             Isim, Irk, Can, Guc);
    }
}

BTW我认为阅读.NET中的Value and Reference Types

对你有用

答案 2 :(得分:0)

我认为问题是你将struct作为变量传递给第一个方法,但struct是值类型 - 即它们被复制,而不是通过引用传递。

struct更改为class将具有您需要的行为。

P.S。你有没有理由选择struct?它们通常用于更高级的场景,开发人员更多地了解使用此类型的好处和缺陷。

答案 3 :(得分:0)

您可能需要考虑使用类而不是结构。

答案 4 :(得分:0)

如上所述,struct是一种值类型并通过副本传递。你可以通过ref传递它:

public static void Move (ref Character a)
{
...
}

并将其称为:

var a = new Character();
MainClass.Move(ref a);

答案 5 :(得分:0)

如果要将结构传递给方法以使该方法对其进行修改,则该方法必须对参数使用ref限定符。如果将结构传递给没有ref参数的方法,则该方法无法修改该结构的任何字段。

请注意,有些人可能会建议用类替换struct,这样就不必使用ref限定符。这是一个危险的概念,因为接收对可变类对象的引用的每个方法都可以自由地在此后的任何时间使对象发生变异。在没有允许收件人改变它的情况下,没有干净的方法来传递对可变类对象的引用,也没有任何方法可以确定给出类对象引用的代码不会持久化它并使用它来修改它任何未来任意时间的对象。结构没有这些问题。

如果对象包含值类型字段,例如MyBounds类型的Drawing.Rectangle,我致电Foo(MyBounds)我可以放心,Foo不可能改变MyBounds。此外,如果我致电Bar(ref MyBounds),我可以预期Bar可能会更改MyBounds,但在方法返回之前,所有更改都将完成。如果Rectangle是可变类类型,那么在不检查FooBar的情况下,我无法知道MyBounds的属性是否可能在任意时间更改在将来。

不理解结构与类不同的人可能会对结构行为的方式感到困惑,但所有具有暴露公共字段的结构行为都是相同的,所以如果理解了结构如何结构工作,人们将理解它们。结构有一个邪恶的方面,即结构上定义的实例方法和属性将接收this作为ref参数,但如果尝试执行类似的操作:

readonly System.Drawing.Rectangle myRect = whatever;
...
myRect.Offset(4,2);

系统会识别myRect无法作为ref参数传递(因为它是只读的),并且在没有任何诊断的情况下,将代码更改为:

readonly System.Drawing.Rectangle myRect = whatever;
...
System.Drawing.Rectangle temp = myRect;
temp.Offset(4,2);

然而,那里的邪恶并不是Rectangle可变的事实,而是编译器假定在调用任何和所有值类型方法时上述代码替换是合法的这一事实。除非或直到Microsoft开始添加一个属性来指示在只读结构上调用特定方法应该导致错误而不是执行此类替换,否则编写对结构进行操作的结构方法的唯一安全方法是“in- “将使用像static void Offset(ref Rectangle it, int x, int y);这样的格式,在这种情况下,Rectangle.Offset(ref myRect, 4, 2);会失败。