【问题标题】:Overloading properties in C#在 C# 中重载属性
【发布时间】:2010-04-09 15:55:52
【问题描述】:

好的,我知道 C# 不支持属性重载 - 大多数参考资料都通过引用单方法不同返回类型问题来解释它。但是,二传手呢?我想直接将值作为字符串或对象赋值,但只作为字符串返回。

像这样:

    public string FieldIdList
    {
        get { return fieldIdList.ToString(); }
        set { fieldIdList = new FieldIdList(value); }
    }

    public FieldIdList FieldIdList 
    {
        set { fieldIdList = value; }
    }
    private FieldIdList fieldIdList;

为什么不允许这样做?我还看到“属性”只是在编译时创建 getter/setter 函数。是否有可能创建我自己的?比如:

    public void set_FieldIdList(FieldIdList value)
    {
        fieldIdList = value;
    }

那会做同样的事情。想法?

【问题讨论】:

  • 我被同样的问题所困扰,并且对语言的这种限制感到非常失望(因为我认为没有理由)。奇怪的是,属性是我在 C++ 中错过的很酷的 C# 语言特性,而我发现它们非常缺乏。

标签: c# properties overloading


【解决方案1】:

属性实际上是一对 get/set 方法(其中一个可能会被省略),但属性本身具有额外的元数据,这使其首先成为属性,而不仅仅是两个方法。

因为根据 only-different-by-return-type,属性签名仍然无效,即使您只有一个 setter。如果你需要这个,不要使用属性;无论如何,只设置属性并不是一件好事。

【讨论】:

  • 那么,编译器为一对方法创建了一个签名,这就是防止额外重载的原因?这只是让属性变得方便还是有更多的好处?哪些附加数据使其成为属性?
  • 不完全是。就像你不能有两个不同类型的变量同名一样,你不能有两个不同类型但同名的属性。问题是一样的,编译器不知道在什么情况下使用哪个变量或属性。因此,即使您选择访问器以便 get/set 方法不会产生冲突,如果签名相同,编译器也不允许您多次使用相同的属性名称(请注意,您可能有多个索引器属性,因为在这种情况下签名确实不同,即使名称相同)。
  • @Lucero:如果属性的类型是由get方法的返回类型强加的?在这种情况下,我们可以有多种类型的 setter,set 方法的主体处理必要的转换。编译器没有混淆,我们仍然得到强类型,因为 set 方法是根据方法重载规则选择的,而不是需要使用 object 属性来接受任何东西来解决提问者的问题(和我的一样,因为它是)。
  • @paercebal,这一切都很好,但这会导致其他问题,例如如何处理虚拟和抽象属性等。事实是,属性是一种最多允许一个 getter 和一个 getter 的构造setter 每个都有明确定义的签名。如果这不合适,那么一定不要使用属性,而是恢复到一堆 ob setter 方法,然后你可以重载它们。
  • @Lucero: how to deal with virtual and abstract properties? 由于 getter 和 setter 是方法,它们的抽象虚拟性应该不是问题。 a property is a construct which allows up to one getter and one setter each with a clearly defined signature :正是我的观点。我相信 setter 的值类型被限制为 getter 的返回类型这一事实是一个设计决定(好或坏,没关系),而不是技术限制。下一个问题是:在 C# 语言中添加重载 setter 的可能性不是很容易吗?
【解决方案2】:

一种方法(您自己可能会争论这是否是一个好的设计选择)是添加第二个属性,它以不同的形式访问数据。

但是,由于它将解析字符串(做大量工作),最好不要为此使用属性,而是添加允许您以字符串形式获取/设置数据的方法。

我会选择提供 ToString() 和 TryParse() 接口的 fieldIdList - 如果你需要它作为一个字符串,你会调用 myObject.FieldIdList.ToString() 等。这会整齐地封装所有内容,允许你转换在代码中的任何位置,而不是仅在作为其他类的成员访问 FieldIdLists 时,从字符串格式到/从,并使客户端代码非常清晰易懂。

【讨论】:

  • string 过载是一个例子,不是一般情况。提问者希望为 A 和 B 类型的属性的 set 方法提供重载,无论它们的类型如何。假设他们“转换”为属性的真正基础类型不是“重要的工作”。那么在 C# 恕我直言,使用属性将是一个很好的自然解决方案。
  • @paercebal:作为最佳实践,属性应该具有没有副作用的简单实现 - 程序员应该能够将属性视为简单的成员变量(也就是说,假设设置它将快速/高效、无损且不会引发事件或异常)。在任何其他情况下,最好将其作为一种方法来实现。属性的重载意味着属性 一个重要的实现,并且隐藏了某种程度的复杂性。这不会总是不好,但经常是。
  • 我理解“最佳实践”的借口,但是让编译器强制执行它似乎没用而且过分,因为:1. 糟糕的程序员总是会写出糟糕的属性,无论涉及多少编译器限制@ 987654323@ 它限制了优秀的程序员做正确的事情。 . . 3. 我是唯一一个觉得属性不能被重载但仍然可以被覆盖(通过使其virtual)这一事实很有趣/矛盾的人吗?
  • 选择 在编译器中“强制执行”这一点的情况,还是它根本不是一个足够有用的功能来证明实现支持的成本是合理的它在编译器中?我们不能仅在返回类型上重载方法,那么为什么这也适用于属性似乎不寻常呢?
  • We can't overload a method on return type alone :对于 getter 方法来说是正确的,但对于 setter 方法来说是题外话,它返回一个 void,并且有一个类型化的参数。根据C#语言规范,属性不是存储位置,而是一组访问器方法:属性P的getter/setter的真实名称定义为T get_P()和voidset_P(T value),为什么不能我们添加了原型set_P(T2 value)? 的重载设置器。总而言之,setter 的过载在我看来是一个简单的句法问题,而不是技术或语义问题。
【解决方案3】:

如果您希望能够将属性设置为字符串或对象,那么您只需使用 object 作为属性的类型,因为它是基类(您可以将字符串传递给接受目的)。这似乎不是特别好的设计决策,但可以做到。也许您需要进一步解释您要达到的目标?

【讨论】:

  • 提问者很清楚:他想为 set 方法提供方法重载。 这和编写多个重载的SetField(Field field)SetField(string field) 方法一样合法。
  • @DanDiplo 使用对象并没有真正的帮助,因为 OP 只想接受两种类型,字符串和自定义 FieldIdList。
【解决方案4】:

不能从 C#7 开始重载 C# 属性。

但是,可能重新设计包括您的资产。

您可以使用 set 块中的条件来调用私有函数, 可以重载。

public string FieldIdList
{
    get { return fieldIdList.ToString(); }
    set { fieldIdList = ChangeFieldList(value); }
}

private string ChangeFieldIdList(int i) {
    return i.ToString();
}

这个例子只是为了展示使用私有函数的重新设计考虑 在 set 块内调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-12
    • 2021-12-27
    • 1970-01-01
    • 2011-06-17
    • 2012-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多