隐式转换不可分配给接口

Implicit conversion not assignable to interface

我有一个 class 从 string 隐式转换定义为:

class TestClass : ITestInterface
{
    public static implicit operator TestClass(string value)
    {
        return new TestClass(value);
    }

    public TestClass(string value)
    {
        Value = value;
    }
    public string Value { get; set; }
}

它实现了一个标记接口:

public interface ITestInterface { }

我有另一个class的方法定义为:

public void DoSomething(ITestInterface thing) { }

我在尝试调用该方法时遇到错误:

public void Test()
{
    TestClass a = "This works fine.";
    DoSomething("Why doesn't this work?");
}

cannot convert from 'string' to 'Tests.ITestInterface'

所有代码都大大简化;我的实际要求要复杂得多,但这似乎是阻止我想要实现的模式的核心。

是什么阻止了它的工作? (C# 规范中的内容?)
是否可以对我的代码进行任何更改以允许这种类型的转换工作?

编译器错误很清楚,不是吗? DoSomething 需要一个 ITestInterface 的实例,string 没有实现。事实上,从字符串到您的 class 的隐式转换并不能使此转换也适用于实现该接口的任何其他 class。

假设有另一个 class 实现了接口:

class AnotherTestClass : ITestInterface { }

现在如何解决 DoSomething-呼叫?转换应适用于哪个 class?到 TestClass 的实例还是 AnotherTestClass?特别是如果 AnotherClass 还定义了隐式转换运算符。这就是为什么这不起作用。

或者反过来考虑:当你只有接口而根本没有实现它的 class 时(这在你设计 API 时很常见),没有转换根本。您的设计引入了一些从接口到具体实现的静态绑定,这是一件坏事。事实上,这使得您的 DoSomething 方法仅适用于类型 TestClass 的实例,这与使用接口作为参数相矛盾。因此,但是使用您的 API 只能使用向您的方法提供 TestClass 的实例。

除此之外,我怀疑演员表在这里不是一件好事。通过隐式转换,您意味着 每个 字符串都可以安全地转换为您的 class 而不会丢失任何信息。例如。 URI 是您的 class 的有效表示吗?或者甚至是您提供的 "Why doesn't this work?"

另一方面,期望字符串的构造函数更加精确且清晰:

var m = new TestClass(myString);

根据我的经验,只有极少数情况下您确实需要隐式转换。你经常做的是根据一些输入创建一些实例,然后 append 一些更多的数据到那个实例。在您的示例中,这意味着 TestClass 包含一些字符串信息,但也可能包含更多数据。

public void DoSomething(ITestInterface thing) { }

因为参数是一个接口,你想调用static implicit operator TestClass(string value)但是不可能。 C#中的接口不能有static方法。 您只能将 class TestClass 作为参数传递

public static void DoSomething(TestClass thing) { Console.WriteLine(thing.Value); }

您忽略了解释问题的第三个选项:

//1
TestClass a = "This works fine.";

//2
ITestInterface i = "This doesn't work either!";

//3
DoSomething("Why doesn't this work?");

(1) 中,您已声明 TestClass a。这意味着编译器知道当您使用不同的类型(在本例中为字符串)时,它应该尝试将所述值转换为 TestClass.

(2) 中,您已声明 ITestInterface i。这意味着编译器知道当您使用不同的类型(在本例中为字符串)时,它应该尝试将所述值转换为 ITestInterface.

这就是问题的根源。 stringITestInterface 之间没有定义转换。

您目前的想法是:

Well, I know that I want this to be converted to a TestClass. Why doesn't the compiler figure out what I want it to do?

对此的简短回答是 编译器拒绝猜测

你想要发生的事情会导致不可能的情况。例如,如果有第二个 class 也实现了 ITestInterface,会发生什么?

class SecondTestClass: ITestInterface
{
    public static implicit operator SecondTestClass(string url)
    {
        return new SecondTestClass(url);
    }

    public SecondTestClass(string url)
    {
        Value = GetValueFromTheInternet(url);
    }
    public string Value { get; set; }
}

让我们重新评估您的代码:

//1
TestClass a = "This works fine.";

这行得通。有一个从 stringTestClass 的转换。

//2
SecondTestClass b = "This works fine.";

这行得通。有一个从 stringSecondTestClass 的转换。

//3
ITestInterface i = "This still doesn't work!";

//4
DoSomething("This doesn't work for the same reason as //3");

这行不通。编译器没有任何已知的从 stringITestInterface.

的转换

编译器无法确定您是希望将其转换为 TestClass 然后分配给 i,还是希望将其转换为 SecondTestClass ] 然后赋值给 i.

而且,正如我之前所说,编译器拒绝猜测。

此外,为了清楚起见,这会起作用:

TestClass a = "This works fine.";

ITestInterface i1 = a;
DoSomething(a);
DoSomething(i1);

SecondTestClass b = "This works fine.";

ITestInterface i2 = b;
DoSomething(b);
DoSomething(i2);

所有这些分配都有效。

问题的症结在于编译器希望您明确说明您希望将字符串转换为哪种类型。在您自己的示例中,您已经明确要求 TestClass。请注意,如果您使用 var,这将不会起作用,因为在那种情况下编译器也无法计算出来。