Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用泛型实现显式接口成员_C#_Generics_Covariance - Fatal编程技术网

C# 用泛型实现显式接口成员

C# 用泛型实现显式接口成员,c#,generics,covariance,C#,Generics,Covariance,我有一个到泛型类组的非泛型接口。我有一个方法,它使用协方差返回从非泛型类组的抽象实现派生的类中的强类型实例 因此,基本上通过这种设置,我有很多类,例如ActualThing1和ActualThing2。这些类有一个Clone方法,该方法返回自身的强类型克隆 下面是我如何构造接口和类的。我不确定这是否正确。 通常,我根本不会使用非泛型抽象类。但这是必要的,因为在这种情况下,我必须对子对象做一些事情,引用内部方法\u内部需要的东西。这不能使用接口来完成,因为它是受保护的,也不能从泛型类内部完成,因为

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

因此,基本上通过这种设置,我有很多类,例如
ActualThing1
ActualThing2
。这些类有一个
Clone
方法,该方法返回自身的强类型克隆

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

这是可行的,但对我来说意义不大的是在我的抽象
Something
类中需要的
ISomething.Clone
的显式实现。它必须存在,但不应该实现,因为我希望实现推迟到从它派生的泛型类。但是没有像
抽象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 ISomething.Clone()
{
抛出新异常(“这不应该发生”);
}
保护内部所需的东西;
}
公共抽象类Something:Something,ISomething其中T:ISomething,new()
{
公共摘要T克隆();
ISomething ISomething.Clone()
{
返回克隆();
}
}
公共接口IActualThing{}//这可以是任何接口
公开课实战:什么,我实战
{
公共覆盖实际克隆()
{
返回新的ActualThing();//在此处执行克隆
}
}

添加所需的方法作为克隆的实现是否适合您? (我仍然不确定您的整个问题是什么,这只会解决抽象-显式接口实现的语法问题。)


首先,我认为在某些内容中有两个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
    }     
} 
公共抽象类某物:某物,某物 其中T:ISomething,new() { 公共覆盖克隆() { 返回新的T().Clone(); //或者,可能必须在此处使用Activator.CreateInstance() } }
其次,我不完全清楚内在需要的东西是抽象的还是虚拟的,但也没有标记。我的解释是它应该是虚拟的,但也许你需要调整一下。无论如何,这是一个总体方案,对我来说似乎很有效,也最有意义。请注意,我能够在抽象类“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(); 
    }
} 
公共接口IActualThing
{
}
公共接口
{    
等轴复制();
}  
公共抽象类某物:等轴物
{
公共抽象克隆();
受保护的虚拟空间\u内部需要的某些内容()
{
抛出新的NotImplementedException();
}
}  
公共抽象类Something:Something,ISomething其中T:ISomething,new()
{    
公共覆盖克隆()
{
返回新的T().Clone();
} 
}  
公开课实战:什么,我实战
{     
公共覆盖克隆()
{
抛出新的NotImplementedException();
}
} 

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

我认为这可能更有效:

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() 
    {
    }
}
公共接口
{
等轴复制();
}
公共抽象类某物:等轴物
{
受保护的抽象克隆内部();
ISomething ISomething.Clone()
{
返回克隆内部();
}
}
公共抽象类Something:Something,ISomething其中T:ISomething,new()
{
受保护的覆盖克隆内部()
{
返回克隆();
}
公共摘要T克隆();
}
公开课实战:什么,我实战
{
公共覆盖实际克隆()
{
}
}

您对
抽象ISomething.Clone
的投诉是有效的,但接口中没有规定必须显式声明它们。下面的代码显示了一个工作示例,并删除了泛型类的要求

interface Igloo
{
    Igloo Clone();
}

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

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

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

在第一位代码中,Clone需要返回
T
,而不是
ISomething
,这是
interface Igloo
{
    Igloo Clone();
}

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

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