【问题标题】:implicit operator on generic types泛型类型的隐式运算符
【发布时间】:2010-09-29 15:32:17
【问题描述】:

使用如下隐式运算符有什么问题吗:

//linqpad c# program example
void Main()
{
    var testObject = new MyClass<int>() { Value = 1 };

    var add = 10 + testObject; //implicit conversion to int here
    add.Dump(); // 11
}

class MyClass<T>
{
    public T Value { get; set; }
    public static implicit operator T (MyClass<T> myClassToConvert)
    {
        return myClassToConvert.Value;
    }
}

我在想我可以通过这种方式将对象的实例视为值类型,但鉴于我从未见过这样的示例,我想也许有一个理由这样做有人可以指出这样的事情吗?

在我的实际代码中,我正在考虑将其作为数据抽象层的一部分,以便我可以返回带有描述底层数据的信息的对象,但允许逻辑代码在需要时将其视为值类型要知道的是值,同时使用泛型保持良好和类型安全。

【问题讨论】:

    标签: c# generics implicit-conversion


    【解决方案1】:

    如果满足以下所有条件:

    • 所有您的MyClass&lt;T&gt; 类型的可能值(包括null,如果它不是值类型!)映射到T 的有效值

      李>
    • 隐式运算符从不抛出(即使null!)

    • 隐式转换具有语义意义,不会让客户端程序员感到困惑

    那么这并没有错。当然,您可以做这三件事中的任何一件,但这将是糟糕的设计。特别是,抛出的隐式运算符可能很难调试,因为调用它的地方并没有说明它正在被调用。

    例如,考虑T? 没有到T 的隐式转换(其中T 当然是一个值类型)。如果存在这样一个隐式运算符,则必须在 T? 为 null 时抛出,因为没有明显的值可以将 null 转换为对于 any 值类型 @987654330 有意义的值@。


    举个例子,我在调试隐式运算符抛出的问题时遇到了麻烦:

    public string Foo()
    {
        return some_condition ? GetSomething() : null;
    }
    

    在这里,GetSomething 返回了我编写的类型,它具有到string 的用户定义的隐式转换。我绝对确定GetSomething 永远不会返回null,但我得到了NullReferenceException!为什么?因为上面的代码等价于

    return some_condition ? (string)GetSomething() : (string)null;
    

    但要

    return (string)(some_condition ? GetSomething() : (Something)null);
    

    现在您可以看到null 的来源!

    【讨论】:

    • 我不确定我是否理解对可空类型的担忧......在我看来,如果你有 n = new MyClass(){Value=null};并且消费代码尝试执行类似 int i=n; 的操作。它会抛出与任何错误类型转换相同的异常,这里的可空类型没什么特别的吧?
    • @asawyer:这只是一个例子。想象一下没有T?,而必须实现你自己的Nullable&lt;T&gt;。你会给它一个隐式转换为T吗?我的回答解释了为什么你不应该这样做,以及为什么 real T? 不这样做。
    • 我现在明白了,正是这些类型的担忧首先引发了这个问题。看起来我应该可以继续,但要非常谨慎。
    【解决方案2】:

    这是一个很棒的模式。请记住,为了将其用作T 类型的变量,您必须将其显式转换为T,或将其分配给T 类型的变量。转换将在采用T 的方法调用和其他事情(例如您的添加示例)中自动进行。

    Implicit conversion without assignment?

    【讨论】:

    • @Timwi,你确定吗? MyClass&lt;T&gt; myClass,此时,myClass.* 将仅解析 MyClass&lt;T&gt; 上的成员,而不解析 T 上的成员。您必须按照 arootbeer 的说明进行操作,并执行 ((T)myClass).* 才能访问 T 本身的任何成员。
    • 几天前我问了这个问题。 stackoverflow.com/questions/3703555/…
    • @Kirk:我知道。 是真的。但是这个答案中的陈述仍然是错误的。例如,您可以在需要T 参数的方法调用中使用MyClass&lt;T&gt;。或者在二元运算符中,例如问题中的示例。或者在returnyield return 语句中。或或或...
    • @Timwi - 我已经编辑了我的声明,以解决您对其正确性的担忧。
    • @Timwi,当然,arootbeer 最好将其表述为“您必须将其显式转换为T 或在推断T 的位置使用它,例如变量或T 类型的参数。"
    猜你喜欢
    • 2012-04-25
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    相关资源
    最近更新 更多