Steztric
Steztric

Reputation: 2942

Tell compiler that implicit conversion exists for generic type

Consider the following code;

class SomeType1
{
}

class SomeType2
{
}

class CombinedType
{
    public static implicit operator CombinedType(SomeType1 source)
    {
        return new CombinedType
        {
            ...
        };
    }

    public static implicit operator CombinedType(SomeType2 source)
    {
        return new CombinedType
        {
            ...
        };
    }
}

void SomeMethod()
{
    var listOfType1 = new List<SomeType1>();
    DoSomethingWith(listOfType1);

    var listOfType2 = new List<SomeType2>();
    DoSomethingWith(listOfType2);
}

void DoSomethingWith<T>(IEnumerable<T> stuff)
{
    IEnumerable<CombinedType> converted = stuff.Select(i => (CombinedType) i);
    ...
}

This fails with

Error CS0030 Cannot convert type 'T' to 'CombinedType'

However, I know that an implicit conversion exists between T and CombinedType when T is either SomeType1 or SomeType2. How can I tell the compiler that this should be possible? I cannot add where T : CombinedType on the generic method because that is not true.

Upvotes: 0

Views: 113

Answers (2)

canton7
canton7

Reputation: 42245

Implicit conversions are just method calls which are inserted by the compiler at compile time.

For example:

CombinedType c = new SomeType1();

gets turned into:

CombinedType c = CombinedType.op_Implicit(new SomeType1());

The JIT doesn't have the knowledge to insert these method calls. Yet, generics are expanded at JIT-time, which is when you want this to happen.

Don't forget that your code also allows someone to pass in a T which isn't convertible to a CombinedType.


You've got a few options, however.

One is:

void DoSomethingWith<T>(IEnumerable<T> stuff)
{
    IEnumerable<CombinedType> converted = stuff.Select(i => i switch
    {
        SomeType1 s1 => (CombinedType)s1,
        SomeType2 s2 => (CombinedType)s2,
        _ => throw ...
    });
}

Another is something like:

public interface IConvertibleToCombinedType
{
    CombinedType ConvertToCombinedType();
}

public class SomeType1 : IConvertibleToCombinedType
{
    // ... or get rid of the implicit conversion, and put the logic here
    public CombinedType ConvertToCombinedType() => this;
}

public class SomeType2 : IConvertibleToCombinedType
{
   ...
}

void DoSomethingWith<T>(IEnumerable<T> stuff) where T : IConvertibleToCombinedType
{
    IEnumerable<CombinedType> converted = stuff.Select(i => ConvertToCombinedType());
    ...
}

Upvotes: 3

Troy
Troy

Reputation: 567

You could create a shared dummy interface like interface ICombinedType {}, make all 3 classes implement it, and then add where T : ICombinedType to the generic method.

Upvotes: 0

Related Questions