自动属性和结构不混合?

Mik*_*lum 64 c# struct automatic-properties c#-3.0

在回答这篇文章的同时踢了一些小结构,我意外地遇到了以下情况:

使用int字段的以下结构是完全合法的:

struct MyStruct
{ 
    public MyStruct ( int size ) 
    { 
        this.Size = size; // <-- Legal assignment.
    } 

    public int Size; 
}
Run Code Online (Sandbox Code Playgroud)

但是,使用自动属性的以下结构无法编译:

struct MyStruct
{ 
    public MyStruct ( int size ) 
    { 
        this.Size = size; // <-- Compile-Time Error!
    } 

    public int Size{get; set;}
}
Run Code Online (Sandbox Code Playgroud)

返回的错误是"在将所有字段分配给"之前,不能使用'this'对象.我知道这是结构的标准过程:任何属性的支持字段必须直接从结构的构造函数中指定(而不是通过属性的set访问器).

解决方案是使用显式支持字段:

struct MyStruct
{ 
    public MyStruct(int size)
    {
        _size = size;
    }

    private int _size;

    public int Size
    {
        get { return _size; }
        set { _size = value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

(请注意,VB.NET不会出现此问题,因为在VB.NET中,所有字段在首次创建时会自动初始化为0/null/false.)

在C#中使用带有结构的自动属性时,这似乎是一个不幸的限制.从概念上思考,我想知道这是不是一个合理的地方,有一个异常,允许在struct的构造函数中调用属性集访问器,至少对于自动属性?

这是一个小问题,几乎是一个边缘案例,但我想知道其他人对此的看法......

Mar*_*ell 83

从C#6开始:这不再是一个问题


在C#6中,您需要调用默认构造函数才能使其工作:

public MyStruct(int size) : this()
{
    Size = size;
}
Run Code Online (Sandbox Code Playgroud)

这里一个更大的问题是你有一个可变的结构.这绝不是一个好主意.我会成功的:

public int Size { get; private set; }
Run Code Online (Sandbox Code Playgroud)

并非技术上不可变的,但足够接近.

使用最新版本的C#,您可以改进:

public int Size { get; }
Run Code Online (Sandbox Code Playgroud)

现在只能在构造函数中分配.

  • 使用绝对值绝不是一个好主意;-p(看看我在那里做了什么......).实际上,*如果您了解其含义*,可变结构可用.问题是大多数人不理解他们,并且他们花费了大量的时间和挫折感. (8认同)
  • @ dotnetN00b是的,你应该!提示:整数,双精度和浮点数都是不可变的:p没有问题重新分配整个值(除了在线程场景中可能是原子); 问题是当你在原地编辑单个值的**部分**时,这通常会导致编辑丢失,除非你非常小心. (6认同)
  • 我想说*从来没有*有点强.一个人应该默认为不可变的,但这听起来像是一个"永远不是一个好主意".;) (4认同)

Sto*_*net 10

您可以通过首先调用默认构造函数来解决此问题:

struct MyStruct 
{
    public MyStruct(int size) : this() 
    {
        this.Size = size; // <-- now works
    }

     public int Size { get; set; }
}
Run Code Online (Sandbox Code Playgroud)


Dan*_*nov 8

对于这个问题的另一个模糊的解决方法是TupleManaged Extensibility Framework(通过KrzysztofKoźmic)的临时类中发现的一个:

public struct TempTuple<TFirst, TSecond>
{
    public TempTuple(TFirst first, TSecond second)
    {
        this = new TempTuple<TFirst, TSecond>(); // Kung fu!
        this.First = first;
        this.Second = second;
    }

    public TFirst First { get; private set; }
    public TSecond Second { get; private set; }
Run Code Online (Sandbox Code Playgroud)

(来自Codeplex的完整源代码:Tuple.cs)

我还注意到CS0188的文档已更新为添加:

如果在尝试初始化结构构造函数中的属性时看到此错误,则解决方案是更改构造函数参数以指定支持字段而不是属性本身.应该在结构中避免自动实现的属性,因为它们没有支持字段,因此无法以任何方式从构造函数初始化.

所以我认为这意味着当你遇到这个问题时,官方指导是在你的结构中使用旧式属性,这可能比目前为止探索的其他两个替代方案中的任何一个都不那么模糊(并且更易读).

  • 我必须说,"knung fu"系列非常酷.(无法用类来完成.)但这与将构造函数声明为'public TempTuple(TFirst first,TSecond second):this()'相同,我认为这是一种更简洁的方法.(我们仍然最终初始化每个字段*两次*.) (3认同)