Интерфейсы с маркерами

У меня есть три маркерных интерфейса для методов расширения свободного 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:
}
Другие вопросы по тегам