【问题标题】:c# implement interface method with parameter of subclass typec#实现带有子类类型参数的接口方法
【发布时间】:2013-04-11 13:16:14
【问题描述】:

我有这个想要的类层次结构:

interface IClass
{
    string print(IClass item);
}

class MyClass : IClass
{
    // invalid interface implementation
    // parameter type should be IClass not MyClass
    string print(MyClass item)
    { return item.ToString(); }
}

我尝试通过使用泛型类型来解决接口实现问题,但没有成功:

interface IClass
{
    string print<T>(T item) where T : IClass;
}

class MyClass : IClass
{
    string print<T>(T item) where T : MyClass
    { return item.ToString(); }
}

我该怎么办?

【问题讨论】:

  • 你应该使接口本身通用,并为实现类提供所需的类型。
  • 打印方法中不带参数如何让每个子类将IClass实现注入到contructor或serter中。
  • toString 方法继承自 Object,那么为什么你真的需要 print(MyClass item) 而不仅仅是 print(Object item)?你隐藏这个方法吗?
  • 这只是我真实类层次结构的简化示例。

标签: c# class-hierarchy


【解决方案1】:

让你的界面通用

interface IClass<T>  where T : IClass<T>
{
     string print(T item);
}

class MyClass : IClass<MyClass>
{
    public string print(MyClass item)
    { 
       return item.ToString(); 
    }
}

【讨论】:

  • 请注意,虽然这确实有效,但 (1) 它会令人困惑,并且 (2) 它不一定会强制执行您希望强制执行的限制。有关此模式的一些想法,请参阅 blogs.msdn.com/b/ericlippert/archive/2011/02/03/…
  • @Eric,你有什么建议以更清晰的方式解决问题?
  • 我们可以在这个解决方案中使用多态性吗?
【解决方案2】:

了解为什么这是非法的会很有帮助。您想要的功能是形式参数类型协方差,很少有语言提供它。 (埃菲尔,我认为这是一个特性。)它在语言中并不常见,因为它不安全!我举个例子来说明:

class Animal {}
class Lion : Animal { public void Roar() { } }
class Giraffe : Animal { }
interface IFoo { void M(Animal a); }
class C : IFoo
{
    public void M(Lion lion) { lion.Roar(); }
}
class P
{
    public static void Main()
    {
        IFoo foo = new C();
        foo.M(new Giraffe()); 
    }
}

我们刚刚发出了长颈鹿的吼声。

如果您查看所有这些类型转换,唯一可以合理认定为非法的转换是将C.M(Giraffe) 匹配到IFoo.M(Animal)

现在,形参类型 逆变typesafe 但它在 C# 中是不合法的,除非在一些非常有限的情况下。如果 C# 支持它,但它不支持,那么您可以安全地执行以下操作:

interface IBar { void M(Giraffe g); }
class D : IBar
{
    public void M(Animal animal) { ... }
}
class P
{
    public static void Main()
    {
        IBar bar = new D();
        bar.M(new Giraffe()); 
    }
}

看看那里发生了什么? IFoo.M 说“我可以带一只长颈鹿”,而 C.M 说“我可以接受任何长颈鹿,因为事实上我可以接受任何动物”。如果 C# 支持它,那将是类型安全的,但它仅以两种方式支持它:

  • 逆变泛型委托和接口转换。
  • 逆变方法组转换为委托类型。

第一个例子是IComparable&lt;Animal&gt; 类型的表达式可以通过相同的逻辑分配给IComparable&lt;Giraffe&gt; 类型的变量:可以使用比较两只动物的方法,其中比较两只长颈鹿的方法是需要。这是在 C# 4 中添加的。

第二个例子是:

delegate void MyFunction(Giraffe g);
...
D d = new D();
MyFunction myfunc = d.M;

同样,我们需要一个接收 Giraffe 的函数,我们提供一个接收任何 Animal 的函数。此功能是在 C# 2 中添加的。

【讨论】:

    【解决方案3】:

    您只需将 IClass 作为参数传递给您的方法。

    interface IClass
    {
      string print(IClass item);
    }
    
    class MyClass : IClass
    {
      public string print(IClass item)
      { return item.ToString(); }
    }
    

    【讨论】:

    • 我的要求是 MyClass 的 print 方法应该接收完全 MyClass 而不是另一个 IClass 子类的参数。
    • 现在,如果我们忽略应该编程接口而不是实现。以下界面有什么问题?接口 IClass { string print(MyClass item); }
    • 没什么。没关系。但就像下面说的@Eric Lippert 令人困惑
    【解决方案4】:

    这是一个至少可以让你编译的解决方案:

    interface IClass
    {
        string print<T>(T item) where T : IClass;
    }
    
    class MyClass : IClass
    {   
        string print(IClass item) => item is MyClass i ? i.ToString() : string.Empty;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-18
      • 2016-01-27
      • 2016-01-06
      • 1970-01-01
      相关资源
      最近更新 更多