Типовые ограничения на реализации универсальных членов неуниверсальных интерфейсов в C # - PullRequest
8 голосов
/ 14 февраля 2010

Допустим, у меня есть такой интерфейс:

interface IAwesome
{
    T DoSomething<T>();
}

Есть ли способ реализовать метод DoSomething с ограничением типов? Очевидно, это не сработает:

class IncrediblyAwesome<T> : IAwesome where T : PonyFactoryFactoryFacade
{
    public T DoSomething()
    {
        throw new NotImplementedException();
    }
}

Это, очевидно, не сработает, потому что этот DoSomething () не будет полностью удовлетворять контракту IAwesome - он будет работать только для подмножества всех возможных значений параметра типа T. Есть ли способ, чтобы эта работа не соответствовала какая-то «чёрная магия» (что я и собираюсь сделать в крайнем случае, если ответ «нет»)?

Честно говоря, я не думаю, что это возможно, но мне интересно, что вы, ребята, думаете.

РЕДАКТИРОВАТЬ : Интерфейс, о котором идет речь, System.Linq.IQueryProvider , поэтому я не могу изменить сам интерфейс.

Ответы [ 3 ]

7 голосов
/ 14 февраля 2010

Нет, это не может работать по проекту, поскольку это будет означать, что контракт на IAwesome не будет (полностью) выполнен.

Пока IncrediblyAwesome<T> реализует IAwesome, разрешено делать это:

IAwesome x = new IncrediblyAwesome<Something>()

Очевидно, что с вашим дополнительным ограничением это может не сработать, поскольку пользователь IAwesome не может знать о наложенных на него ограничениях.

В вашем случае единственное решение, о котором я могу подумать, - это (проверка во время выполнения):

interface IAwesome { // assuming the same interface as in your sample
    T DoSomething<T>();
}

class IncrediblyAwesome<TPony> : IAwesome where TPony : PonyFactoryFactoryFacade {
    IAwesome.DoSomething<TAnything>() {
        return (TAnything)((object)DoSomething()); // or another conversion, maybe using the Convert class
    }

    public TPony DoSomething() {
        throw new NotImplementedException();
    }
}
2 голосов
/ 14 февраля 2010

Разве что-то подобное не поможет?

interface IAwesome<U>
{
    T DoSomething<T>() where T : U
}

class IncrediblyAwesome<T> : IAwesome<PonyFactoryFactoryFacade>
{
    public T DoSomething()
    {
        throw new NotImplementedException();
    }
}

Я не уверен, что это компилируется.

1 голос
/ 14 февраля 2010

Как вы уже упоминали, такое решение не может работать.

Более того, ваш пример нарушает контракт по-другому: один экземпляр IncrediblyAwesome всегда связан с одним конкретным потомком PonyFactoryFactoryFacade (кстати, я бы действительно интересовался целью этот класс :-)). Следовательно, конкретная реализация DoSomething будет не универсальным методом, указанным в интерфейсе, но всегда будет возвращать один единственный тип. Вы не можете написать:

IAwesome a = new IncrediblyAwesome<SomePonyFacadeFactory1>();
SomePonyFacadeFactory2 facade2 = a.DoSomething<SomePonyFacadeFactory2>();

, хотя обе фабрики фасадов происходят от PonyFactoryFactoryFacade ...

Еще один комментарий: я бы держался подальше от кастинга черной магии, так как эти проблемы присущи вашему дизайну, а не просто недостатку C # ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...