自动属性和结构不能混合?

发布于 2024-07-11 12:59:19 字数 1127 浏览 9 评论 0原文

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

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

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

    public int Size; 
}

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

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

    public int Size{get; set;}
}

返回的错误是“在将 'this' 对象的所有字段分配给之前,无法使用该对象”。 我知道这是结构的标准过程:任何属性的支持字段都必须从结构的构造函数中直接分配(而不是通过属性的设置访问器)。

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

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

    private int _size;

    public int Size
    {
        get { return _size; }
        set { _size = value; }
    }
}

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

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

这是一个小问题,几乎是一个边缘情况,但我想知道其他人对此有何看法......

Kicking around some small structures while answering this post, I came across the following unexpectedly:

The following structure, using an int field is perfectly legal:

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

    public int Size; 
}

However, the following structure, using an automatic property does not compile:

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

    public int Size{get; set;}
}

The error returned is "The 'this' object cannot be used before all of its fields are assigned to". I know that this is standard procedure for a struct: the backing field for any property must be assigned directly (and not via the property's set accessor) from within the struct's constructor.

A solution is to use an explicit backing field:

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

    private int _size;

    public int Size
    {
        get { return _size; }
        set { _size = value; }
    }
}

(Note that VB.NET would not have this issue, because in VB.NET all fields are automatically initialized to 0/null/false when first created.)

This would seem to be an unfortunate limitation when using automatic properties with structs in C#. Thinking conceptually, I was wondering if this wouldn't be a reasonable place for there to be an exception that allows the property set accessor to be called within a struct's constructor, at least for an automatic property?

This is a minor issue, almost an edge-case, but I was wondering what others thought about this...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

青衫负雪 2024-07-18 12:59:19

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

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

     public int Size { get; set; }
}

You can fix this by first calling the default constructor:

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

     public int Size { get; set; }
}
绻影浮沉 2024-07-18 12:59:19

此问题的另一个晦涩的解​​决方法是在 托管扩展性中的临时 Tuple 类中发现的解决方法框架(来自Krzysztof Koź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; }

Codeplex 的完整源代码:Tuple.cs< /a>)

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

如果您在尝试时看到此错误
初始化结构体中的属性
构造函数,解决方案是更改
要指定的构造函数参数
支持场而不是
财产本身。 自动实现
应避免的属性
结构,因为它们没有支持
场,因此不能
以任何方式从
构造函数。

我认为这意味着官方指导是在遇到这个问题时在结构中使用旧式属性,这可能比其他两个问题更不晦涩(并且更易读)迄今为止探索的替代方案。

Another obscure work-around to this problem is one spotted in the temporary Tuple class in the Managed Extensibility Framework (via Krzysztof Koź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; }

(Full source code from Codeplex: Tuple.cs)

I also note that the documentation for CS0188 has been updated to add:

If you see this error when trying to
initialize a property in a struct
constructor, the solution is to change
the constructor parameter to specify
the backing field instead of the
property itself. Auto-implemented
properties should be avoided in
structs because they have no backing
field and therefore cannot be
initialized in any way from the
constructor.

So I take that to mean that the official guidance is to use old-style properties in your structs when you run in to this problem, which is probably less obscure (and more readible) than either of the other two alternatives explored so far.

萌无敌 2024-07-18 12:59:19

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


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

public MyStruct(int size) : this()
{
    Size = size;
}

这里更大的问题是您有一个可变结构。 这绝不是一个好主意。 我会做到:

public int Size { get; private set; }

技术上不是一成不变的,但足够接近。

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

public int Size { get; }

现在只能在构造函数中进行赋值。

From C# 6 onward: this is no longer a problem


Becore C# 6, you need to call the default constructor for this to work:

public MyStruct(int size) : this()
{
    Size = size;
}

A bigger problem here is that you have a mutable struct. This is never a good idea. I would make it:

public int Size { get; private set; }

Not technically immutable, but close enough.

With recent versions of C#, you can improve on this:

public int Size { get; }

This can now only be assigned in the constructor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文