У меня есть базовый класс, который определяет такой общий метод:
public class BaseClass
{
public T DoSomething<T> ()
{ ... }
}
Поскольку этот класс принадлежит третьей стороне и не имеет интерфейса, я определяю интерфейс, который определяет действительно необходимые методы этого класса. Таким образом, я получаю слабую связь и фактически могу заменить этот сторонний класс чем-то другим. Для этого примера рассмотрим следующий интерфейс:
public interface ISomething
{
T DoSomething<T> ()
where T : Foo;
}
Как видите, он определяет тот же метод, но также применяет ограничение типа к параметру типа, которое вытекает из некоторых других требований, не имеющих отношения к этому.
Затем я определяю подтип BaseClass
, который также реализует ISomething
. Этот класс будет использоваться как обычная реализация за интерфейсом, в то время как интерфейс будет тем, к чему будет обращаться остальная часть приложения.
public class Something : BaseClass, ISomething
{
// ...
}
Поскольку DoSomething
в BaseClass
уже поддерживает любой параметр типа T
, он должен особенно поддерживать параметр типа, который является подтипом Foo
. Таким образом, можно было бы ожидать, что подтип BaseClass
уже реализует интерфейс. Однако я получаю следующую ошибку:
Ограничения для параметра типа 'T' метода 'BaseClass.DoSomething()' должны совпадать с ограничениями для параметра типа 'T' метода интерфейса 'ISomething.DoSomething()'. Вместо этого рассмотрите возможность использования явной реализации интерфейса.
Теперь у меня есть две возможности; первый - сделать то, что предлагает ошибка, и явно реализовать интерфейс. Второй — скрыть базовую реализацию с помощью new
:
// Explicit implementation
T ISomething.DoSomething<T> ()
{
return base.DoSomething<T>();
}
// Method hiding
public new T DoSomething<T>()
where T : Foo
{
return base.DoSomething<T>();
}
Оба работают, хотя я, вероятно, предпочел бы второе решение, чтобы метод оставался доступным из самого класса. Однако он по-прежнему оставляет следующий вопрос:
Зачем мне заново реализовывать метод, если базовый тип уже реализует его с менее строгим (читай: без) ограничением типа? Почему метод должен быть реализован именно так, как он есть?
Изменить: чтобы придать методу больше смысла, я изменил тип возвращаемого значения с void
на T
. В моем реальном приложении у меня есть как общие аргументы, так и возвращаемые значения.
Something
какBaseClass
, может попытаться вызватьDoSomething
с параметром типа, который не наследуетFoo
. - person JosephHirn   schedule 30.01.2013Foo
дляISomething
. Это сложно продемонстрировать на вашем примере, потому что это просто действие. Но представьте, чтоDoSomething<T>
вернул экземплярT
. Как вы гарантируете, что возвращаемое значениеDoSomething<T>
унаследовано отFoo
? - person JosephHirn   schedule 30.01.2013T DoSomething<T>()
реализовано вBaseClass
, то я могу быть уверен, что получуFoo
, если вызовуDoSomething<Foo>()
. - person poke   schedule 30.01.2013T
s. - person poke   schedule 30.01.2013