Generics IAbstract <T> наследуется от IAbstract
Я пытаюсь добиться чего-то подобного:
interface IAbstract
{
string A { get; }
object B { get; }
}
interface IAbstract<T> : IAbstract
{
T B { get; }
}
class RealThing<T> : IAbstract<T>
{
public string A { get; private set; }
public T B { get; private set; }
}
Итак, я могу сделать что-то вроде этого:
RealThing<string> rt = new RealThing<string>();
IAbstract ia = rt;
IAbstract<string> ias = rt;
object o = ia.B;
string s = ias.B;
Возможно ли это?
Ответы
Ответ 1
Очень близко. Три вещи:
-
Вы должны использовать new
в IAbstract<T>
, чтобы указать, что вы знаете, что скрываете существующего участника:
new T B { get; }
Но даже без этого вы все равно получите предупреждение.
-
Вам нужно реализовать IAbstract.B
внутри RealThing
, который вы почти наверняка будете делать, используя явную реализацию интерфейса, делегируя строго типизированному члену:
object IAbstract.B { get { return B; } }
-
В вашем тестовом коде вам нужно указать аргумент типа для RealThing
:
RealThing<string> rt = new RealThing<string>();
Это хорошо и даже достаточно распространенный шаблон времени, когда вы хотите получить не-общую форму интерфейса.
Ответ 2
Да, с небольшими изменениями
interface IAbstract
{
string A { get; }
object B { get; }
}
interface IAbstract<T> : IAbstract
{
new T B { get; }
}
sealed class RealThing<T> : IAbstract<T>
{
public string A { get; private set; }
public T B { get; private set; }
object IAbstract.B
{
get { return B; }
}
}
чтобы вы могли написать
var rt = new RealThing<string>();
IAbstract ia = rt;
IAbstract<string> ias = rt;
object o = ia.B;
string s = ias.B;
Ответ 3
Фактически интерфейсы System.Collections.IEnumerator
и System.Collections.IEnumerator<T>
делают это. Когда вы реализуете IEnumerable<T>
, вам нужно будет реализовать один из свойств Current
явно, обычно вы выбираете для него не общее:
object IEnumerable.Current
{
// this calls the implicitly implemented generic property
get { return this.Current; }
}
public T Current
{
get { return this.current; } // or however you want to do it
}
Ответ 4
В этом случае вам даже не нужны два интерфейса. Просто пометьте интерфейс как ковариантный (поддерживается с С# 4):
interface IAbstract<out T>
{
string A { get; }
T B { get; }
}
и используйте IAbstract<object>
, где раньше вы использовали не общий интерфейс.