【问题标题】:Implementing explicit interface members with generics使用泛型实现显式接口成员
【发布时间】:2011-09-28 16:43:18
【问题描述】:

我有一个泛型类组的非泛型接口。我有一个方法,它使用协方差在派生自非泛型类组的抽象实现的类中返回强类型实例。

所以基本上有了这个设置,我有很多课程,例如ActualThing1 和 ActualThing2。这些类有一个Clone 方法,该方法返回自身的强类型克隆。

以下是我如何构建接口和类。我不确定这是否正确。 通常,我根本不会有非泛型抽象类。但这是必要的,因为在某些情况下我必须对子对象做一些事情,引用一个内部方法_SomethingNeededInternally。这不能使用接口完成,因为它是受保护的,也不能从泛型类内部完成,因为子类可能不是同一类型(它们可能是从接口派生的不同类型)。因此,非泛型基类Something。

这可行,但对我来说不太有意义的是我的抽象 Something 类中需要的 ISomething.Clone 的显式实现。它必须在那里,但不应该实现,因为我希望将该实现推迟到派生自它的泛型类。但是没有 abstract ISomething ISomething.Clone() 这样的语法。

但是那个代码(抛出异常的地方)永远无法执行,可以吗,因为我没有这个对象的任何非泛型实现?

我想我想知道是否有更好的方法来做到这一点,因为它似乎不对。也就是说,我依赖于这样一个事实,即永远不会从接口创建非泛型类,这闻起来很有趣。

public interface ISomething
{
    // ...
    ISomething Clone();
}

public abstract class Something: ISomething 
{
    ISomething ISomething.Clone()
    {
        throw new Exception("This should not be happening");
    }
    protected int _SomethingNeededInternally;
}

public abstract class Something<T>: Something, ISomething where T: ISomething, new()
{
    public abstract T Clone();

    ISomething ISomething.Clone()
    {
        return Clone();
    }
}

public interface IActualThing {} // this could be any interface

public class ActualThing: Something<ActualThing>, IActualThing
{
    public override ActualThing Clone() 
    {
        return new ActualThing(); // do cloning here
    }
}

【问题讨论】:

  • 你的 ISomething 接口是故意内部的?
  • 不,这不应该是公开的。已编辑。
  • 如果代码实际上是可编译的,它会更容易阅读。建议的编辑(待批准)。答案中重复出现编译错误,因此难以评估。
  • @Roman Boiko - 这是伪代码,因此不应该是完整的,但只是为了好玩,我尝试按原样编译它。它对我来说编译得很好,我没有看到任何语法错误。你觉得哪里不对?
  • 哦,我看到你编辑了,没关系。

标签: c# generics covariance


【解决方案1】:

将所需的方法添加为克隆的实现对您有用吗? (我仍然不确定你的整个问题是什么,这只会解决抽象显式接口实现的语法。)

public abstract class Something: ISomething  
{ 
    ISomething ISomething.Clone() 
    { 
        return CloneYouMust();
    } 
    abstract ISomething CloneYouMust();
}

【讨论】:

  • 我认为你和 Magnus 基本上是在提出同样的建议。这很有意义,很简单。你是第一个。
  • 顺便说一句,虽然这确实有效,但我也突然想到我实际上不必让Something 继承ISomething。由于我只需要在类的实现中使用它,我很确定没有理由不删除接口??
【解决方案2】:

我认为这可能会更好:

public interface ISomething
{
    ISomething Clone();
}

public abstract class Something : ISomething 
{
    protected abstract ISomething CloneInternal();

    ISomething ISomething.Clone()
    {
        return CloneInternal();
    }
}

public abstract class Something<T>: Something, ISomething where T: ISomething, new()
{
    protected override ISomething CloneInternal()
    {
        return Clone();
    }

    public abstract T Clone();
}

public class ActualThing: Something<ActualThing>, IActualThing
{
    public override ActualThing Clone() 
    {
    }
}

【讨论】:

  • Alexe 的回答几乎相同,他是第一个,所以他为你 +1,谢谢。
【解决方案3】:

您对abstract ISomething ISomething.Clone 的投诉是有效的,但没有关于接口声明您必须明确 声明它们的任何内容。下面的代码显示了一个工作示例,并删除了泛型类的要求。

interface Igloo
{
    Igloo Clone();
}

abstract class Alpha : Igloo
{
    public abstract Igloo Clone();
}

class Bravo : Alpha
{
    public override Igloo Clone()
    {
        /* implement */
        return null;
    }
}

【讨论】:

  • 但我希望 Bravo 返回 Bravo 而不是 Igloo
  • 他可能希望 Clone 函数返回与派生类中的对象相同的类型,这就是泛型的原因。
【解决方案4】:

首先,我认为在 Something 中有两个 Clone() 方法是多余的。既然您已经将 T 限制为 ISomething 和 new(),为什么不这样做:

public abstract class Something<T>: Something, ISomething 
       where T: ISomething, new() 
{     
    public override ISomething Clone()    
    {
        return new T().Clone(); 

        //alternatively may have to use Activator.CreateInstance() here
    }     
} 

其次,我并不完全清楚 _SomethingNeededInternally 是否需要是抽象的或虚拟的,但它也没有被标记。我的解释是它应该是虚拟的,但也许你需要调整它。无论如何,这里的总体方案似乎对我来说效果很好并且最有意义。请注意,我能够在抽象类“Something”中将 Clone() 方法抽象化:

public interface IActualThing
{
}

public interface ISomething 
{    
    ISomething Clone(); 
}  

public abstract class Something: ISomething  
{
    public abstract ISomething Clone();

    protected virtual void _SomethingNeededInternally()
    {
        throw new NotImplementedException(); 
    }
}  

public abstract class Something<T>: Something, ISomething where T: ISomething, new()
{    
    public override ISomething Clone()    
    {
        return new T().Clone(); 
    } 
}  

public class ActualThing: Something<ActualThing>, IActualThing 
{     
    public override ISomething Clone()      
    {
        throw new NotImplementedException(); 
    }
} 

另请注意,您需要在最终的“ActualThing”类中将返回类型标记为 ISomething。当然,您实际上会返回一个“ActualThing”,但该方法仍然需要符合接口。

【讨论】:

  • 在第一段代码中,Clone 需要返回 T 而不是 ISomething,这是整个混乱的基础。
  • Clone 确实返回 T。T 被限制为 ISomething 的新实例。在我看来,如果那不是预期的功能,也许你的约束不应该存在。类 Something 不能调用任何完全实现的 Clone() 版本,因为它没有一个可以调用..
【解决方案5】:

我建议您定义和实现接口 ISelf,包含一个 T 类型的 Self 属性,以及 ICloneable,派生自 ISelf,使用 T 类型的方法 Clone()。然后实现 ICloneable 的类可以使用返回 ItsOwnType 的方法来实现它;该方法应该调用一个虚拟的 InternalClone 方法来完成实际工作(否则,对基类型的变量调用 Clone 可能最终会调用基类型的 Clone 方法而不是派生方法)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-11
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-07
    相关资源
    最近更新 更多