微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

抽象类和接口具有相同的泛型方法

如何解决抽象类和接口具有相同的泛型方法

| 我正在编写两个我的许多项目都将使用的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 {

    }
}
这两个API都需要此搜索方法。第二个API在调用
IMyInterface.Search<T>()
的其他类中具有某些功能,我希望那些继承
MyBaseClass
的类使用
MyBaseClass
中定义的
Search<T>
函数。 编译错误方法\'MyBaseClass.Search()\'的类型参数\'T \'的约束必须与接口方法\'IMyInterface.Search()\'的类型参数\'T \'的约束匹配。考虑改用显式接口实现。 注意:调用Search时,T将始终是继承了任何抽象类或接口的派生类。这是我在C#2.0(C#抽象类返回派生类型枚举器)中实现此目标的唯一途径,这只会引起更多问题! 是否有一种无需使用对象和强制转换即可实现类型安全的方法? 解: 基于Andras Zoltan接受的答案,我在项目中创建了此类,并且必须为同时使用这两个API的每个项目重新创建此类。
public abstract class ApiAdapter<TAdapter> : MyBaseClass,IMyInterface where TAdapter: MyBaseClass,IJsonObject,new()
{
    IEnumerable<T> IJsonObject.Search<T>()
    {
        foreach (TAdapter row in base.Search<TAdapter>())
            yield return (T)(IMyInterface)row;
    }
}
然后,我像这样继承此类。
public class Client : ApiAdapter<Client> {
    //everything else can go here
}
    

解决方法

我首先从解释为什么它不适合您的问题开始,但是我认为现在已经很了解了,所以我将其省略。 我赞成@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>
  { }
} 
    ,您可以显式实现接口Search方法,例如
    public class MyDerivedClass : BasicTestApp.FirstApi.MyBaseClass,BasicTestApp.SecondApi.IMyInterface
    {
        IEnumerable<T> SecondApi.IMyInterface.Search<T>()
        {
            // do implementation
        }
    }
但是,我认为您是在将处理对象的代码部分(如ѭ11)调用
Search<T>
方法时要求调用
MyBaseClass
Search方法。我看不到办法,因为您有两个
T
类型,它们具有不同的约束,因此无法关联。 如果您在Search方法的两个定义中都做了“ 14”,那么您就不会有问题,但这会将您的两个API捆绑在一起 这是您显式实现的接口方法的可能实现。它无法避免演员表转换,但至少可以使其保持整洁。
        IEnumerable<T> SecondApi.IMyInterface.Search<T>()
        {
            var results = base.Search<MyDerivedClass>();

            return results.Cast<T>();
        }
    ,我认为您可以执行接口的显式实现,以及何时将通过IMyInterface.Search访问方法-编译器将运行正确的方法。     ,您需要使用显式实现。
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>();
    }     
}
由于实现方式不同,因此很有意义。如果它们没有不同,则基类应该实现该接口,并且您应该使用协方差(仅.Net 4.0)来组合约束,或者也许根本不需要该接口。     ,希望我不要困惑,您能不能更改您的定义,例如:
public interface IMyInterface<in T>
{
    //some property and method signatures

    IEnumerable<U> Search<U>() where U : T,new();
}
提供
T
的通用参数,可用于强制执行该实现为
T
类型提供搜索功能约束:
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>();
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。