C# 使用相同泛型方法抽象类和接口

C# 使用相同泛型方法抽象类和接口,c#,generics,inheritance,architecture,C#,Generics,Inheritance,Architecture,我正在编写两个API,我将在我的许多项目中使用它们。有些项目使用其中一种API,有些使用另一种API,但我的大多数项目将同时使用这两种API。我试图把它们设计成完全分开的样子,但我在一件事上苦苦挣扎 namespace FirstApi { public abstract class MyBaseClass { //constructor, some methods and properties public IEnumerable<T> S

我正在编写两个API,我将在我的许多项目中使用它们。有些项目使用其中一种API,有些使用另一种API,但我的大多数项目将同时使用这两种API。我试图把它们设计成完全分开的样子,但我在一件事上苦苦挣扎

namespace FirstApi {
    public abstract class MyBaseClass {
        //constructor, some methods and properties

        public IEnumerable<T> Search<T>() where T : MyBaseClass, new() {
            //search logic here. must use generics as I create new instances of T here
        }
    }
}


namespace SecondApi {
    public interface IMyInterface {
        //some property and method signatures

        IEnumerable<T> Search<T>() where T : IMyInterface, new();
    }
}

namespace MyProject {
    public class MyDerivedClass : MyBaseClass, IMyInterface {

    }
}
然后我像这样继承这个类

public class Client : ApiAdapter<Client> {
    //everything else can go here
}
公共类客户端:ApiAdapter{
//其他的都可以放在这里
}

我认为您可以显式实现接口,以及何时通过IMyInterface访问methor。Search-编译器将运行正确的方法。

您可以显式实现接口搜索方法,例如

    public class MyDerivedClass : BasicTestApp.FirstApi.MyBaseClass, BasicTestApp.SecondApi.IMyInterface
    {
        IEnumerable<T> SecondApi.IMyInterface.Search<T>()
        {
            // do implementation
        }
    }

您需要使用显式实现

public class MyDerivedClass : MyBaseClass, IMyInterface
{
    // The base class implementation of Search inherited

    IEnumerable<T> IMyInterface.Search<T>()
    {
        // The interface implementation
        throw new NotImplementedException();

        // this would not work because base does not implement IMyInterface 
        return base.Search<T>();
    }     
}
公共类MyDerivedClass:MyBaseClass,IMyInterface
{
//搜索继承的基类实现
IEnumerable IMyInterface.Search()
{
//接口实现
抛出新的NotImplementedException();
//这将不起作用,因为base不实现IMyInterface
返回base.Search();
}     
}

由于实现不同,这是有意义的。如果它们没有区别,那么要么基类应该实现接口,您应该使用协方差(.net4.0)来组合您的约束,要么您根本不需要接口

我在开始回答时解释了为什么它对你不起作用,但我认为现在已经很好地理解了,所以我将省略它

我已经对@IndigoDelta的答案投了赞成票,但它突出了我不喜欢这里的总体设计的一些地方——我有一种潜移默化的怀疑,你实际上应该使用泛型接口和泛型类;不是泛型方法,因为它没有任何意义:

注意:调用Search时,T将始终是继承的抽象类或接口的派生类

我把这个溶液加入混合物中;我认为这更好,因为这意味着每个派生类型都不需要重新实现
IMyInterface.Search
方法,而且它在某种程度上可以实际执行您提到的规则。它是一种专用于将两个API连接在一起的泛型类型,这意味着派生类型不需要执行任何操作:

namespace MyProject
{
  using FirstApi;
  using SecondApi;

  public class SecondAPIAdapter<T2> : MyBaseClass, IMyInterface
    where T2 : SecondAPIAdapter<T2>, new()
  {
    #region IMyInterface Members
    IEnumerable<T> IMyInterface.Search<T>()
    {
      return Search<T2>().Cast<T>();
    }
    #endregion
  }

  //now you simply derive from the APIAdapter class - passing
  //in your derived type as the generic parameter.
  public class MyDerivedClass : SecondAPIAdapter<MyDerivedClass>
  { }
} 
名称空间MyProject
{
使用FirstApi;
使用SecondApi;
公共类SecondAPIAdapter:MyBaseClass,IMyInterface
其中T2:secondapiapter,new()
{
#区域imy接口成员
IEnumerable IMyInterface.Search()
{
返回Search().Cast();
}
#端区
}
//现在,您只需从APIAdapter类传递派生
//在派生类型中作为泛型参数。
公共类MyDerivedClass:SecondApiaAdapter
{ }
} 

我希望我没有被搞糊涂,您能不能不要更改您的定义,例如:

public interface IMyInterface<in T>
{
    //some property and method signatures

    IEnumerable<U> Search<U>() where U : T, new();
}
这样,您的派生类型就是:

public class MyDerivedClass : MyBaseClass
{

}
然后,您可以通过以下方式进行搜索:

var derived = new MyDerivedClass();
IMyInterface<MyDerivedClass> iface = impl;

var results = iface.Search<MyDerivedClass>();
var-derived=new MyDerivedClass();
imy接口iface=impl;
var results=iface.Search();

也许现在是凌晨,我还没有醒来,但我不明白问题出在哪里。为什么你提供的代码不起作用?对不起,我用编译器错误更新了帖子对不起,我也不明白这个问题。也许提供一个与
IMyInterface
MyBaseClass
相反的真实示例会有所帮助。@Mongus-Pong-因为编译器试图用继承的搜索方法实现接口的搜索方法,但这不能因为约束没有实现match@Andras,gottit我错过了这一点。+1这是我想要做的事情-但我试图找到一种不修复类型的方法-如果可能的话,保持它与输入类型相同。因为泛型函数总是期望从其封闭类型派生的类型是没有意义的。对我来说,这听起来像是一个泛型类。我想我喜欢它+1,但为什么不在基类上实现接口呢?@Jodrell我相信这是因为FirstAPI对secondapi一无所知。我想出了一个稍微不同的解决方案,它使用泛型类型。看一看——因为我不喜欢这个(由OPs设计引起的)是需要关闭
Search
参数,这是正确的答案。我遇到的问题是,可能有任意数量的类实现这两个API。在我的一个项目中,我研究了大约60个不同的类,在所有这些类中使用相同的显式方法似乎复制了太多的代码。我担心这可能是唯一的解决办法。这是个好主意。有没有办法绕过它,将我的第二个API接口定义为
interface IMyInterface,其中T:IMyInterface
,并定义派生类,如
MyDerivedClass:MyBaseClass,IMyInterface
?这看起来是理想的解决方案!这也意味着我可以保持两个API的设计得体。我会去试试这个,然后再给你回复。我喜欢这个,它比我发布的解决方案更优雅,可以防止代码重复。
public abstract class MyBaseClass : IMyInterface<MyBaseClass>
{
    public virtual IEnumerable<T> Search<T>() where T : MyBaseClass, new()
    {

    }
}
public class MyDerivedClass : MyBaseClass
{

}
var derived = new MyDerivedClass();
IMyInterface<MyDerivedClass> iface = impl;

var results = iface.Search<MyDerivedClass>();