【问题标题】:Tell compiler that implicit conversion exists for generic type告诉编译器泛型类型存在隐式转换
【发布时间】:2023-03-10 09:00:04
【问题描述】:

考虑以下代码;

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);
    ...
}

这失败了

错误 CS0030 无法将类型“T”转换为“CombinedType”

但是,我知道当TSomeType1SomeType2 时,TCombinedType 之间存在隐式转换。我如何告诉编译器这应该是可能的?我不能在泛型方法上添加where T : CombinedType,因为那不是真的。

【问题讨论】:

  • 你怎么称呼DoSomethingWith?你知道你打电话给它的时候是IEnumerable&lt;SomeType1&gt;还是IEnumerable&lt;SomeType2&gt;

标签: c# generics compiler-errors


【解决方案1】:

隐式转换只是编译器在编译时插入的方法调用。

例如:

CombinedType c = new SomeType1();

变成:

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

JIT 不知道插入这些方法调用。然而,泛型是在 JIT 时扩展的,这是您希望发生的时候。

不要忘记,您的代码还允许某人传入不能转换为 CombinedTypeT


不过,您有几个选择。

一个是:

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

另一个是这样的:

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());
    ...
}

【讨论】:

  • 我认为选项 1 对我有帮助。我在另一个答案中提到我无权访问SomeType1 的来源,因此无法添加其他接口。
  • @Steztric 将这类信息包含在您的问题中会非常有帮助。
  • switch 方法也可以放入CombinedType。即,如果您在 CombinedType 类中放置此方法:public static CombinedType Create&lt;T&gt;(T t) { switch (t) { case SomeType1 st1: return st1; case SomeType2 st2: return st2; default: throw new ArgumentException(); } }(或与 C# 8 语法类似)。然后您可以将您的选择写为:IEnumerable&lt;CombinedType&gt; converted = stuff.Select(CombinedType.Create).
【解决方案2】:

你可以创建一个像interface ICombinedType {}这样的共享虚拟接口,让所有3个类都实现它,然后将where T : ICombinedType添加到泛型方法中。

【讨论】:

  • 会是个好主意,但我实际上无法访问SomeType1 的源代码,它来自一个库。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-10
  • 2013-11-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多