为什么我不能在同一个类中拥有名为"id"和"set_id"的属性?

10
我正在尝试使用一个Web API。我创建了一个类,以便能够对返回的数据进行反序列化。问题在于返回的对象有这两个属性:
public string id { get; set; }
public string set_id { get; set; }

与"sets"相关的set_id。编译器在id属性的set;上抛出一个错误,说它已经包含了对set_id的定义。

CS0102 类型'MyClass'已经包含了一个对'set_id'的定义

有没有办法解决这个问题,而不用重新命名属性呢?


3
我不知道是谁试图关闭这个问题,但这真的是一个相当好的问题。它展示了除了周围的 class Foo { ... } 之外的所有代码。错误很容易复现。我不知道这个问题的解决方案。看起来像是一个 bug。 - Enigmativity
1
如果这个类在你的控制之下,你可以将其重命名为SetId并给它添加属性[JsonPropertyName("set_id")]。参见:https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/customize-properties?pivots=dotnet-7-0 - Orifjon
5
我对这个问题的理解还不够完整,但与属性实际上是语法糖以及编译器生成的中间语言(IL)有关。请在这段IL代码中注意到一个名为set_id的方法被为您生成了。https://sharplab.io/#v2:EYLgZgpghgLgrgJwgZwLQGED2AbbEDGMAlpgHYAyRMECU2yANDCEdgD4ACATAIwCwAKA4BmAATdR6UQG9BASBHieABlFEAJjNEBzCDADco5HsMBfeQHoLijiqN6A+hq26D9t+YGmgA== - gunr2171
@gunr2171 哇,谢谢你的澄清。我本来就觉得可能是这样,但是在任何地方都无法确认。 - Lucas Hoffmann
1
@gunr2171 C#标准在这里解释了:14.3.10.2 保留给属性的成员名称 - undefined
2个回答

13
我建议使用JsonPropertyName。
例如:
using System.Text.Json.Serialization;

    namespace ConsoleApp1
    {
        public class Class1
        {
            public string id { get; set; }
            [JsonPropertyName("set_id")]
            public string setId { get; set; }
        }
    }

根据你的 JSON 库,这个属性可能是基于它的。如果你使用的是 Newtonsoft 库,那么它应该是 JsonProperty
让我们找出为什么我们不能同时使用名称为id和set_id的两个变量。
为了理解这一点,我们将查看C#编译器生成的IL代码。
对于具有1个属性id的类,生成的IL代码如下:
.class public auto ansi beforefieldinit ConsoleApp1.Test
    extends [System.Runtime]System.Object
{
    .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
        01 00 01 00 00
    )
    .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = (
        01 00 00 00 00
    )
    // Fields
    .field private string '<id>k__BackingField'
    .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
        01 00 00 00
    )
    .custom instance void [System.Runtime]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggerBrowsableState) = (
        01 00 00 00 00 00 00 00
    )

    // Methods
    .method public hidebysig specialname 
        instance string **get_id** () cil managed 
    {
        .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
            01 00 00 00
        )
        // Method begins at RVA 0x20b8
        // Header size: 1
        // Code size: 7 (0x7)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldfld string ConsoleApp1.Test::'<id>k__BackingField'
        IL_0006: ret
    } // end of method Test::get_id

    .method public hidebysig specialname 
        instance void set_id (
            string 'value'
        ) cil managed 
    {
        .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
            01 00 00 00
        )
        // Method begins at RVA 0x20c0
        // Header size: 1
        // Code size: 8 (0x8)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldarg.1
        IL_0002: stfld string ConsoleApp1.Test::'<id>k__BackingField'
        IL_0007: ret
    } // end of method Test::set_id

    .method public hidebysig specialname rtspecialname 
        instance void .ctor () cil managed 
    {
        // Method begins at RVA 0x20c9
        // Header size: 1
        // Code size: 8 (0x8)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void [System.Runtime]System.Object::.ctor()
        IL_0006: nop
        IL_0007: ret
    } // end of method Test::.ctor

    // Properties
    .property instance string id()
    {
        .get instance string ConsoleApp1.Test::get_id()
        .set instance void ConsoleApp1.Test::set_id(string)
    }

} // end of class ConsoleApp1.Test

在这段代码中,你可以看到getter和setter方法被转换成了名为set_id和get_id的两个方法(set_id = set,get_id = get)。
现在我们已经保留了set_id和get_id,所以不能再有其他名为set_id或get_id的字段。

太好了,那个完美地解决了问题。非常感谢你。 - Lucas Hoffmann

0
C#编译器生成的代码会创建setter和getter。 对于您的属性id,将会创建set_id。 我建议您将set_id简单地重命名为setIdIdOfSet等等。
通常,在C#中,如果您想遵循接受的代码样式规范,属性名称中不应该使用下划线。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接