【问题标题】:Why implicit operator has to be static?为什么隐式运算符必须是静态的?
【发布时间】:2019-02-06 07:17:39
【问题描述】:

我有一个名为FloatPlugIn 的课程。我希望用户能够做类似的事情

FloatPlugIn x = new FloatPlugIn();
x.Minimum = -100;
x.Maximum = 100;

float y = 123;
x = y;

这就是为什么我决定将implicit operator 添加到我的班级

public static implicit operator FloatPlugIn(float p)
{
    return new FloatPlugIn() { Default = p };
}

问题是隐式运算符必须是静态的,这就是为什么在转换过程中创建我的类的新实例的原因。结果,我丢失了位于“旧”实例内部的所有信息。

有没有办法解决这个问题?我希望将浮点值应用于现有实例,而不是完全替换它。

【问题讨论】:

  • 您不能使用赋值运算符“添加”。如果您作为无辜的开发人员阅读此代码,C# 语义与您期望发生的情况相匹配,而您的意图是颠覆它们。为什么不重载+呢?
  • 我希望将浮点值添加到现有实例中... 那么Add 方法不是更合适吗?
  • x.Default = y; 怎么样?
  • 听起来您确实想在现有实例上设置属性。
  • 没错。 assignment 分配了一个完全独立 实例,因此您当然会丢失该“旧”实例的所有信息。因此,您不需要assignement,而是modification。

标签: c#


【解决方案1】:

我认为您不了解转换的作用——它不是强制转换——它必须创建一个新实例。只有在更新现有实例时才使其成为非静态的才有意义。

【讨论】:

    【解决方案2】:

    assignment operator 的语义需要这种行为。事实上:

    赋值运算符 (=) 将其右侧操作数的值存储在由其左侧操作数表示的存储位置、属性或索引器中,并将该值作为结果返回。操作数必须是同一类型(或者右侧操作数必须隐式转换为左侧操作数的类型)。

    隐式转换运算符的目的不是修改一个目标值——注意可能没有any这样的目标值,例如如果你通过方法参数的值。

    我希望将浮点值添加到现有实例中,而不是完全替换它。

    如果您想要一个 addition(在您的情况下的任何特定含义),请考虑覆盖添加 + 运算符,这反过来会影响 addition assignment += operator。但是,无论如何您都不会取消创建新的 FloatPlugIn 实例。

    假设您在FloatPlugIn 中有以下方法,它将修改现有实例:

    public void Add(float f)
    {
        // do whatever 'addition' means in your case
    }
    

    那么+ 操作符应该是这样工作的:

    public static FloatPlugIn operator +(FloatPlugIn a, float b)
    {
        FloatPlugIn result = a.Clone(); // here Clone() denotes any custom method that creates a copy of that instance
        result.Add(b);
        return b;
    }
    

    在您的代码中,以下内容将起作用:

    FloatPlugIn x = new FloatPlugIn();
    x.Minimum = -100;
    x.Maximum = 100;
    
    float y = 123;
    x += y; // a new instance is created, but the 'addition' logic is preserved
    

    此外,在将值传递给方法调用的情况下,同样可以直观地工作:

    ProcessMyFloatPlugin(x + 123.0f);
    

    您可以看到 这是一个非常好的主意,作为运算符的结果创建 FloatPlugIn 的新实例。否则,对x 的就地修改实际上将是一个令人讨厌的副作用,任何其他开发人员都完全出乎意料。请注意,如果性能(避免动态内存分配)是一个问题,请考虑使用structs。

    【讨论】:

    • 我相信您误解了 OP 中“添加”的含义。他并不是在建议进行数学加法运算,而是要求以某种方式将浮点值与现有实例组合起来。
    • @Enigmativity:运算符重载的“美”(有些人会称之为诅咒)是你不受数学的束缚。 Foo operator+(Foo foo, float p) 基本上可以做任何你想做的事——它甚至可以在修改后返回foo,尽管这会破坏语义,以至于你可能会在使用它时遇到麻烦。这并不是说简单、显式的实例方法不可能是更合适的解决方案——这取决于 FloatPlugIn 是什么类型的东西,以及“添加”浮点数是否有意义。
    • @Enigmativity 我不这么认为。无论OP所说的“加法”是什么意思,都可以。 + 运算符可以很好地表示常识中的“加法”。请参阅我现在提供特定示例的更新答案。如果现在很清楚,那么欢迎取消投票:))
    【解决方案3】:

    我认为在这种情况下,如果您使用 x.Default = y; 或创建一个像这样采用浮点数的构造函数,会更好:

    // Constructor
    public FloatPlugIn(float p)
    {
        Default = p;
    }
    

    用法:

    float y = 123;
    FloatPlugIn x = new FloatPlugIn(y);
    

    【讨论】:

    • 抱歉,这没有回答我的问题。我更喜欢 x.Default = y
    • 如果你仔细看,你会发现 x.Default = y 是我回答中的第一个选择 :-)
    • Right :) 但我希望用户能够像对待普通浮点数一样对待 x 变量,而 x 内部仍然拥有一些额外的信息。
    猜你喜欢
    • 2010-10-26
    • 2014-05-27
    • 1970-01-01
    • 2012-04-11
    • 2011-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-30
    相关资源
    最近更新 更多