代码之家  ›  专栏  ›  技术社区  ›  Bradley Uffner

隐式转换不可分配给接口

  •  1
  • Bradley Uffner  · 技术社区  · 6 年前

    我有一个隐式转换的类 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 { }
    

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

    public void DoSomething(ITestInterface thing) { }
    

    尝试调用该方法时出错:

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

    无法从“string”转换为“tests.itestinterface”

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

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

    3 回复  |  直到 6 年前
        1
  •  5
  •   Flater    6 年前

    你省略了第三个解释这个问题的选项:

    //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 .

    这就是问题的根源。之间没有定义转换 string ITSITE接口 .

    你目前的想法是:

    好, 我想把这个转换成 测试类 . 为什么编译器不知道我想要它做什么?

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

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

    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.";
    

    这是可行的。有一个转换自 一串 测试类 .

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

    这是可行的。有一个转换自 一串 SecondTestClass .

    //3
    ITestInterface i = "This still doesn't work!";
    
    //4
    DoSomething("This doesn't work for the same reason as //3");
    

    这不管用。编译器没有来自的任何已知转换 一串 ITSITE接口 .

    编译器无法确定是否要将其转换为 测试类 然后分配给 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);
    

    所有这些任务都有效。

    问题的关键在于编译器希望您 明确地 说明要将字符串转换为哪种类型。在您自己的示例中,您已经明确要求 测试类 . 注意,如果您使用 var 因为在这种情况下,编译器也无法解决这个问题。

        2
  •  3
  •   MakePeaceGreatAgain    6 年前

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

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

    class AnotherTestClass : ITestInterface { }
    

    怎么会 剂量测定法 -现在呼叫已解决?转换应应用于哪个类?到的一个实例 TestClass AnotherTestClass ?尤其是如果 AnotherClass 还定义了隐式强制转换运算符。这就是为什么这行不通的原因。

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

    除此之外,我怀疑演员阵容在这里是件好事。通过一个隐含的结论,你暗示 每一个 字符串可以安全地转换为类,而不会丢失任何信息。例如,URI是否是类的有效表示形式?甚至你提供的 "Why doesn't this work?" ?

    另一方面,期望字符串的构造函数要精确得多,并使其明确:

    var m = new TestClass(myString);
    

    根据我的经验,只有少数情况下你真的需要一个内隐演员。您经常要做的是基于一些输入创建一些实例,并且 追加 该实例的更多数据。在您的示例中,这意味着 测试类 由一些字符串信息组成,但也可能有更多的数据。

        3
  •  0
  •   Khai Nguyen    6 年前
    public void DoSomething(ITestInterface thing) { }
    

    因为参数是一个接口,您想调用 static implicit operator TestClass(string value) 但这是不可能的。C中的接口不能 static 方法。 你可以通过一门课 TestClass 仅作为参数

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