C # ограничение общего параметра для Tдля интерфейса Fluent / компилятор не может выводить типы - PullRequest
1 голос
/ 07 января 2011

Клиентские классы WCF обычно настраиваются следующим образом:

public class Client : ClientBase<IService>, IService

Я хочу расширить эти клиенты с помощью метода расширения, который является Свободным, чтобы я мог объявить оператор using, например:

using (new Client().WithCookies(...)) {}

Однако я не могу найти способ сохранить исходный тип вызывающей стороны, не создав некоторый довольно неуклюжий синтаксис вызова:

new Client().WithCookies<Client,IService>(...)

Я не уверен, почему компилятор не можетвывести T на основе того, что я передал, но не могу, основываясь на определении метода расширения:

public static T WithCookies<T, TChannel>(this T clientBase, IEnumerable<Cookie> cookies)
   where T : ClientBase<TChannel>, TChannel
   where TChannel : class
{
   HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();
   requestProperty.Headers.Add(HttpCookieHeader, string.Join("; ", cookies.Select(c => c.ToCookieString(false))));

   new OperationContext(clientBase.InnerChannel).OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;
   return clientBase;
}

Я знаю, что Эрик Липперт в своем блоге опровергает идею указания«Мне все равно, что является аргументом типа для универсального» (и, как правило, по уважительным причинам) http://blogs.msdn.com/b/ericlippert/archive/2008/05/19/a-generic-constraint-question.aspx

Псевдо-реализация будет выглядеть примерно так:

public static T WithCookies<T>(this T clientBase, IEnumerable<Cookie> cookies)
   where T : ClientBase<>
{
   HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();
   requestProperty.Headers.Add(HttpCookieHeader, string.Join("; ", cookies.Select(c => c.ToCookieString(false))));

   new OperationContext(clientBase.InnerChannel).OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;
   return clientBase;
}

Thisэто один из сценариев, где он мне подходит, так как я не забочусь , что такое TChannel - я не собираюсь использовать его в своем коде, я просто хочу использовать любую ClientBase <>в качестве ограничения.

С учетом сказанного может кто-нибудь придуматьс творческим способом реализовать мое свободное владение без спецификации типов?

Имейте в виду, что если вы не вернете переданный исходный элемент, вы потеряете способность вызывать методы обслуживания, реализованные в IService.

Ответы [ 3 ]

1 голос
/ 18 января 2011

Эрик Липперт ответил в другой теме -

Общий метод расширения: аргумент типа не может быть выведен из использования

Короткий ответ: вывод компилятора, к сожалению, не работает.

Подробнее в своем блоге: http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx

0 голосов
/ 07 января 2011

Не ответ на вопрос, но что-то, о чем нужно знать, если вам удастся заставить это работать ...

Если вы используете синтаксис using (new Client().WithCookies(...)) и ваш метод WithCookies вызываетисключение, тогда экземпляр Client не будет введен.

0 голосов
/ 07 января 2011

Способ реализации вашей псевдо-реализации будет через отражение.Вы можете сделать это:

  1. Используйте отражение, чтобы посмотреть на clientBase и выяснить, что такое TChannel (подняв иерархию типов и ища ClientBase<TChannel>)
  2. Получить специализированное определение WithCookies, используя typeof(YourClass).GetMethod("WithCookiesImpl").MakeGenericMethod(new[] { typeof(T), channelType })
  3. Вызвать это специализированное определение WithCookies

Для меня вопрос, почему компилятор не может вывести типыв вызове на T WithCookies<T, TChannel>?Он имеет ограничение T : ClientBase<TChannel>;поскольку T может наследовать только от ClientBase один раз, может быть только один TChannel.(Если бы ClientBase был интерфейсом, то могло быть более одного TChannel.)

...