C# 不可分配给接口的隐式转换

C# 不可分配给接口的隐式转换,c#,implicit-conversion,C#,Implicit Conversion,我有一个从字符串隐式转换的类,定义为: class TestClass : ITestInterface { public static implicit operator TestClass(string value) { return new TestClass(value); } public TestClass(string value) { Value = value; } public stri

我有一个从字符串隐式转换的类,定义为:

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 void DoSomething(ITestInterface thing) { }
它实现了一个标记接口:

public interface ITestInterface { }
class AnotherTestClass : ITestInterface { }
我有另一个类的方法,定义为:

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 void DoSomething(ITestInterface thing) { }
尝试调用该方法时出错:

public void Test()
{
    TestClass a = "This works fine.";
    DoSomething("Why doesn't this work?");
}
无法从“字符串”转换为“Tests.ITestInterface”

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

是什么阻止了这一点?C规范中的一些东西?
我是否可以对代码进行任何更改以允许这种类型的强制转换工作?

编译器错误非常清楚,不是吗?DoSomething需要一个ITestInterface实例,该字符串没有实现。从字符串到类的隐式转换并不意味着这种转换也适用于实现接口的任何其他类

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

public interface ITestInterface { }
class AnotherTestClass : ITestInterface { }
现在如何解决DoSomething问题?转换应应用于哪个类?到TestClass的实例还是到另一个TestClass?特别是如果另一个类也定义了隐式强制转换运算符。这就是为什么这不起作用

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

除此之外,我怀疑演员阵容在这里是件好事。通过使用隐式concversion,意味着每个字符串都可以安全地转换为类,而不会丢失任何信息。例如,URI是否是类的有效表示形式?甚至是你提供的为什么这不起作用

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

var m = new TestClass(myString);

根据我的经验,只有极少数情况下,您真正需要隐式转换。您经常做的是基于一些输入创建一些实例,并向该实例附加更多数据。在您的示例中,这意味着TestClass包含一些字符串信息,但也可能包含更多的数据。

编译器错误非常清楚,不是吗?DoSomething需要一个ITestInterface实例,该字符串没有实现。从字符串到类的隐式转换并不意味着这种转换也适用于实现接口的任何其他类

public void DoSomething(ITestInterface thing) { }
假设有另一个类实现了接口:

public interface ITestInterface { }
class AnotherTestClass : ITestInterface { }
现在如何解决DoSomething问题?转换应应用于哪个类?到TestClass的实例还是到另一个TestClass?特别是如果另一个类也定义了隐式强制转换运算符。这就是为什么这不起作用

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

除此之外,我怀疑演员阵容在这里是件好事。通过使用隐式concversion,意味着每个字符串都可以安全地转换为类,而不会丢失任何信息。例如,URI是否是类的有效表示形式?甚至是你提供的为什么这不起作用

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

var m = new TestClass(myString);
根据我的经验,只有极少数情况下,您真正需要隐式转换。您经常做的是基于一些输入创建一些实例,并向该实例附加更多数据。在您的示例中,这意味着TestClass包含一些字符串信息,但也可能包含更多的数据

public void DoSomething(ITestInterface thing) { }
因为参数是一个接口,您希望调用静态隐式运算符TestClassstring值,但这是不可能的。C中的接口不能有静态方法。 您只能将类TestClass作为参数传递

public static void DoSomething(TestClass thing) { Console.WriteLine(thing.Value); }
因为参数是一个接口,您希望调用静态隐式运算符TestClassstring值,但这是不可能的。C中的接口不能有静态方法。 您只能将类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中,你已经声明了它的界面i。这意味着编译器知道,在本例中,当您使用不同类型的字符串时,它应该尝试将所述值转换为ITestInterface

这就是问题的根源。字符串和ITestInterface之间未定义转换

您目前的想法是:

我知道我想把它转换成TestClass。为什么编译器不知道我想要它做什么

简而言之,编译器拒绝猜测

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

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

//1
TestClass a = "This works fine.";
这很有效。有一个从字符串到TestClass的转换

这很有效。存在从字符串到SecondTestClass的转换

这不管用。编译器没有从字符串到ITestInterface的任何已知转换

编译器无法确定是要将其转换为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,这将不起作用,因为在这种情况下编译器也无法计算出来。

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

//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中,你已经声明了它的界面i。这意味着编译器知道,在本例中,当您使用不同类型的字符串时,它应该尝试将所述值转换为ITestInterface

这就是问题的根源。字符串和ITestInterface之间未定义转换

您目前的想法是:

我知道我想把它转换成TestClass。为什么编译器不知道我想要它做什么

简而言之,编译器拒绝猜测

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

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

//1
TestClass a = "This works fine.";
这很有效。有一个从字符串到TestClass的转换

这很有效。存在从字符串到SecondTestClass的转换

这不管用。编译器没有从字符串到ITestInterface的任何已知转换

编译器无法确定是要将其转换为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,这将不起作用,因为在这种情况下编译器也无法计算出来。

虽然存在从字符串到类的隐式转换,但没有从字符串到接口的转换。你必须明确地向你的班级施加压力。然而,对我来说,甚至试着去想给你们的班级拉一根绳子似乎都很奇怪。这样做意味着每个字符串都可以安全地转换为您的类,我怀疑的是您想要的是什么。;似乎对用户更友好me@HimBromBeere在这种特殊情况下,每个字符串都是有效的转换。在我的完整代码中,这是文档表示的一部分。可以通过类似Documentparams IPart[]零件的构造函数创建文档。我试图使包含字符串内容的块与其他类型的内容混合在一起变得容易。但即使是在文档中,我想您也会对该文档中的数据有一些固定的结构。我怀疑我的任意字符串是否是您的类的有效表示形式,是吗?该类专门设计为围绕任意字符串内容的包装器。虽然存在从字符串到您的类的隐式转换,但从字符串到您的接口却没有。你必须明白地说

向你的班级发短信。然而,对我来说,甚至试着去想给你们的班级拉一根绳子似乎都很奇怪。这样做意味着每个字符串都可以安全地转换为您的类,我怀疑的是您想要的是什么。;似乎对用户更友好me@HimBromBeere在这种特殊情况下,每个字符串都是有效的转换。在我的完整代码中,这是文档表示的一部分。可以通过类似Documentparams IPart[]零件的构造函数创建文档。我试图使包含字符串内容的块与其他类型的内容混合在一起变得容易。但即使是在文档中,我想您也会对该文档中的数据有一些固定的结构。我怀疑我的任意字符串是否是您的类的有效表示形式,是吗?该类是专门设计为围绕任意字符串内容的包装器。这里的问题不是由运算符类的静态性质造成的,也不是因为接口无法具有静态成员。如果OP使用的是基类和派生类而不是接口和实现类,那么OP的问题也会发生,此时您的参数不再适用。虽然我认为OP问题的根源在他使用基类时会更加明显。这里的问题不是由操作符类的静态性质造成的,也不是因为接口不能有静态成员。如果OP使用的是基类和派生类而不是接口和实现类,那么OP的问题也会发生,此时您的参数不再适用。虽然我希望OP使用基类时问题的根源会更加明显。谢谢,多个潜在类实现隐式转换的情况是我遗漏的部分。谢谢,多个潜在类实现隐式转换的情况是我遗漏的部分。谢谢,多个潜在类实现隐式转换的情况是我缺少的部分。@BradleyUffner根据您的设计,您有一些从接口到具体类的静态绑定。通常,接口的使用是独立于任何实现的。我试图模仿XElement构造函数使用的相同模式,该模式允许开发人员使用节点、属性和字符串内容构建文档树。我只是想包含更多的类型安全性,XElement使用对象数组。虽然我确实质疑是否需要强制转换,但我不会说使用这两种方法都是不好的。请注意,转换为对象和有效是两个截然不同的特性。我可以做新人{Name=http://google.com }; 也犯错误的可能性本身并不是我不应该公开设置此属性的有效理由。走到极端,这将引导您走上一条不向使用者泄漏基本类型的道路,而是强迫他们使用您的数据类。[..]字符串转换和带有单个字符串参数的构造函数之间的选择是一种风格。隐式转换倾向于通过降低可读性来降低可维护性。然而,如果当前的代码库有大量的字符串到对象转换正在进行,那么从开发人员的角度来看,如果转换是天生可以理解的,那么将代码简化为隐式转换可能是有益的。例如,摘自今天的另一篇文章:机场目的地=LAX;谢谢,多个潜在类实现隐式转换的情况是我缺少的部分。@BradleyUffner根据您的设计,您有一些从接口到具体类的静态绑定。通常,接口的使用是独立于任何实现的。我试图模仿XElement构造函数使用的相同模式,该模式允许开发人员使用节点、属性和字符串内容构建文档树。我只是想包含更多的类型安全性,XElement使用对象数组。虽然我确实质疑是否需要强制转换,但我不会说使用这两种方法都是不好的。请注意,转换为对象和有效是两个截然不同的特性。我可以做新人{Name=http://google.com }; 也犯错误的可能性本身并不是我不应该公开设置此属性的有效理由。走到极端,这将引导您走上一条不向使用者泄漏基本类型的道路,而是强迫他们使用您的数据类。[..]字符串转换和带有单个字符串参数的构造函数之间的选择是一种风格。隐式转换倾向于通过降低可读性来降低可维护性。然而,如果当前的代码库有大量的字符串到对象转换正在进行,那么当转换从源代码本身就可以理解时,将代码简化为隐式转换可能是有益的 开发者的观点。例如,摘自今天的另一篇文章:机场目的地=LAX;