【问题标题】:C# constructor with new and get integerC# 构造函数与 new 并获取整数
【发布时间】:2019-02-10 20:49:51
【问题描述】:

这是 Unity 5.5.0 上的结构 我对 c# 很陌生,不太了解属性和结构。

这会在this.X 期间分配错误。

我假设您不能更改结构上的值,而关键字 this 指的是结构的属性

在将控制权返回给调用者之前,必须完全分配自动实现的属性“Point.X”的支持字段。考虑从构造函数初始化器调用默认构造函数。 (CS0843) (汇编-CSharp) [LN 15]

“this”对象在其所有字段都分配给 (CS0188) (Assembly-CSharp) [LN 16] 之前不能使用。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public struct Point 
{

    // Don't undertstand why "public int X, Y" works fine but not this        
    public int X { get; set; }

    public int Y { get; set; }

    //public int X,Y;

    public Point(int x, int y) 
    { 
        // LN 15
        this.X=x;
        this.Y=y;
    }
}

【问题讨论】:

标签: c#


【解决方案1】:

这是某些 C# 版本的奇怪之处;编译器有时无法正确检测到结构已通过构造函数在所有代码路径上完全初始化。

解决办法是说

public Point(int x, int y) : this()  // default initialization
{ 
  this.X = x;
  this.Y = y;
}

它告诉编译器“字段在构造函数中初始化之前被初始化为其默认值”。

这在我们做 C# 3 的时候有点语言设计的失败;这绝不是你必须做的。对此感到抱歉。

既然我已经引起了你的注意,让我们来谈谈你提出的另一点:

我假设您不能更改结构上的值

可以更改结构上的值,但您不应该。结构应该是:

  • 逻辑值
  • 不可变

所以我的建议是将 setter 设为私有(使用 private set;

您创建了一个可变点结构,这是一种不好的做法。创建一个不可变的点结构,并将它们视为不可变的数学对象,而不是变量的集合。

还有:

关键字this指的是结构的属性

关键字this保存结构实例值的变量的别名。这是微妙的;让我举一个例子。如果我们说:

Point a = new Point(1, 2);

意思是:

  • 创建一个大小为一个点的新临时存储变量。
  • 调用双参数构造函数,将this 设为该临时存储变量的别名,并将 1 和 2 复制到形参 x 和 y 中。
  • 构造函数返回后,将临时变量中的值复制到变量a中。

现在,您可能会注意到这样做似乎更有效率:

  • 调用两个参数的构造函数,使this 成为a 的别名,依此类推。

而且效率会更高;这称为复制省略优化,而 C# 在知道用户不可能注意到差异时会这样做。 (挑战:构建一个 C# 程序,用户可以在其中确定是否使用了复制省略;C# 将不会在这样的程序中复制省略!)

如果你做了类似的事情:

struct Point
{
   ... constructors, whatever ...
   public double DistanceFromOrigin()
   {
     return Math.Sqrt(this.X * this.X + this.Y * this.Y);
   }

当您调用a.DistanceFromOrigin() 时,this 成为a 的别名;它们是同一个变量,只是有两个不同的名称。

不是引用类型的工作方式。在引用类型中,thisreferencecopy。在值类型中,this变量的别名

这些都是微妙的点。

【讨论】:

  • Eric 发布挑战 13 分钟后仍未提出解决方案 8|一定是一个艰难的...
  • @vc74:没那么难。试一试!
  • vc74 认为捕获与它有关的想法很好。例如:struct S{ private int x; private int y; public S(int x, int y, Action a) { this.x = x; a(); this.y = y; } public override string ToString() => (y > 0).ToString(); } 现在假设我们有S s = default(S); s = new S(1, 2, ()=>{}); s = new S(3, 4, ()=>Console.WriteLine(s); 现在我们可以判断副本是否被省略。如果是,并且对s 的第三个赋值是直接改变s,那么y2,所以这会打印True。如果没有删除副本,则 y 在 temp 中仍然为零。
  • @vc74:你有没有在 main 中有一个 try 块,有一个未捕获的异常和一个 finally 块?在那种情况下,发生什么是实现定义的。当有未捕获的异常时,允许程序做任何事情,“运行finally块”包含在“anything”中,“不运行finally块”也是如此。
  • @vc74:不,你没有明白我在说什么。 try-finally 在程序中的哪个位置并不重要。重要的是异常是否被捕获!如果从未捕获到异常,则运行时可以执行任何操作。它可以立即终止进程,它可以启动一个调试器,它可以打电话给微软描述崩溃,它可以运行 finally 块,它不能运行 finally 块,它可以做任何你可以编写程序来做的事情。如果您不喜欢这样,那么捕获所有抛出的异常。未捕获的异常是纯粹的集中邪恶。
猜你喜欢
  • 2017-12-22
  • 1970-01-01
  • 1970-01-01
  • 2012-01-29
  • 2011-04-19
  • 2017-01-04
  • 1970-01-01
  • 2017-05-28
相关资源
最近更新 更多