对于基类的类型约束,即使类型参数是子类,也会调用基类的转换运算符

时间:2012-05-17 21:23:06

标签: c# generics operator-overloading

我正在解决我在解决方案here中重新创建的问题。

问题是我正在使用一些可以隐式地从字符串转换为自身的自定义类型。其中一个自定义类型继承自另一个。

public class CustomType
{
    public string InnerString { get; protected set; }

    public CustomType(string s)
    {
        InnerString = s;
    }

    #region Operator Overloads
    public static implicit operator CustomType(string s)
    {
        if (s == null)
            throw new ArgumentNullException();
        return new CustomType(s);
    }
    public static implicit operator string(CustomType value)
    {
        if (value == null)
            return null;
        return value.InnerString;
    }
    #endregion
}


public class SubCustomType : CustomType
{
    public SubCustomType(string s)
        : base(s)
    {
        // Nada
    }

    #region Operator Overloads
    public static implicit operator SubCustomType(string s)
    {
        if (s == null)
            throw new ArgumentNullException();
        return new SubCustomType(s);
    }
    public static implicit operator string(SubCustomType value)
    {
        if (value == null)
            return null;
        return value.InnerString;
    }
    #endregion
}

在另一个泛型类中,我依赖于基本自定义类型可以隐式地从字符串转换为自身的事实。 (转换发生在第(T)this.Rtf行。.Rtf是一个字符串。)(在我的例子中,泛型类是RichTextBox的子类,因为当我遇到这个问题时,我正在使用它。)

public class CustomRichTextBox<T> : Forms.RichTextBox
    where T : CustomType
{
    public object GetValue()
    {
        /// This line throws:
        /// InvalidCastException
        /// Unable to cast object of type 'TestCustomTypesCast.CustomType' to type 'TestCustomTypesCast.SubCustomType'.
        return (T)this.Rtf;
    }
}

public class SubCustomRichTextBox : CustomRichTextBox<SubCustomType>
{
}

当我使用SubCustomRichTextBox(具有SUB自定义类型作为类型参数的泛型类的实例)时,我在T中转换为GetValue的行中获得InvalidCastException }。我认为正在发生的事情是,为了使编译器可以正常使用T从字符串转换,它正在查看CustomType并看到它的强制转换过载。但即使我使用CustomType的子类作为实际类型参数,编译器仍然期望SubCustomType.CustomType(string s)执行强制转换,而不是正确的SubCustomType.SubCustomType(string s)方法。

有人能指出我解决这个问题的方向吗?我想使用泛型类,因为它允许我重用相同的代码。如果我不能使用泛型,那么我需要在CustomRichTextBox<T>的几个子类中复制代码。感谢。

1 个答案:

答案 0 :(得分:1)

这很难,因为运算符重载是静态的,而你实际上是在尝试获取虚拟行为。

试试这个:

public class CustomRichTextBox<T> : Forms.RichTextBox
    where T : CustomType, new()
{
    public object GetValue()
    {
        T t = new T();
        t.InnerString = this.Rtf;
        return t;
    }
}

注意我已将new()添加到类型约束中。我还必须使InnerString公开可设置。

顺便说一句,您可以将GetValue()的返回类型设为T。这可能是一个更好的API。