Интерфейсы с маркерами
У меня есть три маркерных интерфейса для методов расширения свободного API:
interface IOne { }
interface ITwo { }
interface IOneOrTwo : IOne, ITwo { }
и следующий метод расширения:
public static IOneOrTwo Foo (this IOne obj, string arg)
{
// do something with arg
return obj; // <- possible without cast?
}
Вопрос: возможно ли как-то вернуть obj без кастинга? Обычно в этой ситуации вам необходимо явно уменьшить значение, однако ни один из этих интерфейсов не требует, чтобы базовый объект имел какой-либо метод / свойство / что бы то ни было.
Примечание. Фактический класс реализации реализует все интерфейсы.
Вопрос 2: Почему осуществляется IOne
а также ITwo
не позволяет автоматически реализации быть также типа IOneOrTwo
?
2 ответа
возможно ли как-то вернуть obj без кастинга?
Нет. Просто потому, что класс реализует IOne
не означает, что это также реализует IOneOrTwo
, Так что вам нужно разыграть (что вполне может провалиться)
ни один из этих интерфейсов не требует, чтобы базовый объект имел какой-либо метод / свойство / что бы то ни было.
Это не имеет значения. Отсутствие реальных методов магическим образом не подводит вас. Если объект реализует IOne
технически это могло бы реализовать IOneOrTwo
без добавления каких-либо методов, но все равно необходимо явно включить это в определение класса.
Почему реализует
IOne
а такжеITwo
не позволяет автоматически реализации быть также типаIOneOrTwo
Так как IOneOrTwo
может включать методы, которые не являются частью IOne
или же ITwo
, Просто потому, что объект реализует IOne
а также ITwo
не означает, что он также реализует любой интерфейс, который также включает эти два.
Вы можете получить то, что вы хотите, используя дженерики:
public static T Foo<T> (this T obj, string arg) where T: IOne
{
// do something with arg
return obj;
}
тогда вы могли бы сказать:
IOneOrTwo obj = new IOneOrTwoImpl();
IOneOrTwo obj2 = obj.Foo("gfgfd"); // valid since obj implements IOneOrTwo
но вы не можете сделать:
IOne obj = new IOneImpl();
IOneOrTwo obj2 = obj.Foo("gfgfd"); // not valid since obj does not implement IOneOrTwo
без актерского состава.
Итог - реализации интерфейса должны быть явно объявлены. Тот факт, что класс может реализовывать интерфейс (то есть он содержит все методы / свойства, составляющие этот интерфейс), не означает, что вы можете обращаться с ним так, как будто он реализует этот интерфейс.
Кажется, что ваша реализация может быть отсталой и может ответить на оба ваших вопроса, чтобы иметь IOne
а также ITwo
воплощать в жизнь IOneOrTwo
а не наоборот.
interface IOneOrTwo { }
interface IOne: IOneOrTwo { }
interface ITwo: IOneOrTwo { }
//*** This should now work fine ***
public static IOneOrTwo Foo (this IOne obj, string arg)
{
// do something with arg
return obj;
}
Разъяснение:
//This extension method is available to IOne, ITwo, and IOneOrTwo
public static IOneOrTwo Foo2 (this IOneOrTwo obj, string arg)
{
// do something with arg
return obj:
}
//This extension method is available only to IOne
public static IOne Foo2 (this IOne obj, string arg)
{
// do something with arg
return obj:
}
//This extension method is available only to ITwo
public static ITwo Foo2 (this ITwo obj, string arg)
{
// do something with arg
return obj:
}