Я пишу два 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
, использовали функцию Search<T>
, определенную в MyBaseClass
.
Ошибка компиляции: Ограничения для параметра типа 'T' метода 'MyBaseClass.Search ()' должны соответствовать ограничениям для параметра типа 'T' метода интерфейса 'IMyInterface.Search ( ). Попробуйте вместо этого использовать явную реализацию интерфейса.
Примечание: Когда вызывается Search, T всегда будет производным классом любого абстрактного класса или интерфейса, унаследованного. Это был единственный способ добиться этого в C # 2.0 ( C # абстрактный класс возвращает перечислитель производного типа ), и это только вызвало больше проблем!
Есть ли безопасный для типов способ, которым я могу достичь этого без использования объектов и приведения?
Решение:
Основываясь на принятом ответе Андраса Золтана, я создал этот класс в своем проекте, и мне придется заново создавать этот класс для каждого проекта, использующего оба 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
}