简体   繁体   中英

Is there a way to define implicit conversion operators in C# for specific versions of generic types?

I have a generic class, MyClass<T> , and I want to be able to implicitly convert from some type, eg bool , to a specific version of the generic type, eg MyClass<string> . It seems I cannot use any of the following:

  • fails because "Using the generic type 'MyClass<T>' requires '1' type argument(s)":

    public static implicit operator MyClass(bool value) { return new MyClass<string>(value.ToString()); }

  • fails because "Unbound generic name is not valid in this context" and because "User-defined conversion must convert to or from the enclosing type":

    public static implicit operator MyClass<>(bool value) { return new MyClass<string>(value.ToString()); }

  • fails because "User-defined conversion must convert to or from the enclosing type":

    public static implicit operator MyClass<string>(bool value) { return new MyClass<string>(value.ToString()); }

  • fails because "Cannot implicitly convert type 'MyClass<string>' to 'MyClass<T>'":

    public static implicit operator MyClass<T>(bool value) { return new MyClass<string>(value.ToString()); }

Is there any way this can be achieved, or will I just have to live without it (and incur explicit calls to a conversion method everywhere)?

No, you can't do this. The C# specification is clear, your implicit operator must convert either to or from the type in which it's declared. It has to be an exact conversion, and since the declaring type is exactly MyClass<T> , the conversion has to be either to or from that.

See eg Can i use a generic implicit or explicit operator? C# and C# Implicit operator with generic .

At the risk of condoning or endorsing an XY Problem , here are a couple of hacky alternatives:

// Break generics by checking the type explicitly. Requires ugly casting
// and intermediate boxing, though it's possible that with some run-time
// use of Expressions, you could cache a delegate that would handle the
// conversion without the boxing. It'd still be ugly though.
class Class1<T>
{
    public Class1(T t) { }

    public static implicit operator Class1<T>(bool value)
    {
        if (typeof(T) == typeof(string))
        {
            return (Class1<T>)(object)(Class1OfString)value;
        }

        throw new InvalidOperationException("Invalid type T");
    }
}

// Subclass the generic, and declare the conversion there. Of course, then
// to use the conversion, you have to reference this type explicitly. Ugly.
class Class1OfString : Class1<string>
{
    public Class1OfString(string text) : base(text) { }

    public static implicit operator Class1OfString(bool value)
    {
        return new Class1OfString(value.ToString());
    }
}

class A
{
    public static void M()
    {
        // These all compile and execute fine
        Class1OfString c1 = true;
        Class1<string> c2 = (Class1OfString)true;
        Class1<string> c3 = true;
    }
}

There are a number of variations on the themes above, but they all will involve circumventing and special casing the type in some way.

It is worth pointing out that, besides the difficulty dealing with the generic vs. specific here, the use of implicit is suspect for other reasons. The documentation states right at the top that one should use implicit only "if the conversion is guaranteed not to cause a loss of data" and implementations "should never throw exceptions" . In both cases, this is "so that they can be used safely without the programmer's awareness" . In other words, the very nature of implicit is that they get invoked implicitly, without the programmer necessarily even thinking about it. So they must always work, which wouldn't necessarily be the case with some of the examples above (and in one example, you have to use an explicit syntax anyway, so you might as well implement the operator as explicit anyway).

None of these options are ideal. But frankly, neither is the original scenario. It is odd for a generic type to have to deal with concrete types on a specific basis. It calls into question whether the generic type really should be generic in the first place. It is possible that you really should be doing something more like the subclassing example above, only applied further. Ie use the generic type for whatever base behavior you need, but put all your specializations into a subclass where you know the type parameter T .

I can't offer more advice than that, given the lack of details in the question. But the basic request is shaky enough to suggest that, if only the question had included a broader problem statement and details about what led you to this actual implementation goal, a better and more applicable answer might have been provided.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM