WCF Generics. Почему DataContract и CollectionDataContract допускают форматированное именование, но не DataMember, OperationContract или ServiceContract?

В основном, как следует из названия:

[DataContract(Name = "{0}Item")] //This will format properly
public class GenericItem<T>
{
    [DataMember(Name = "The{0}")] //This will NOT format properly
    public T TheItem { get; set; }
}

[CollectionDataContract(Name = "{0}Items")] //This will format properly
public SpecialCollection<T> : Collection<T> { }

[ServiceContract(Name = "{0}Service")] //This will NOT format properly
public interface IGenericService<T>
{
    [OperationContract(Name = "Get{0}")] //This will NOT format properly
    GenericItem<T> Get<T>();
}

Итак, вот оно... что работает, а что нет... но вопрос в том... почему? Очевидно, что .NET может создавать конкретный тип и форматировать имя, когда используя DataContract и CollectionDataContract и указывая тип (т.е. GenericItem<Foo> или SpecialCollection<Foo>. Так почему бы не сделать так, чтобы DataMember тоже не форматировалось?

ServiceContract/OperationContract я могу понять так, как он оставлен выше (типа), но чего я не понимаю, так это того, что когда вы даете ему конкретный тип, операции все равно не будут работать должным образом:

[ServiceContract(Name = "FooService")]
public interface FooService : IGenericService<Foo> { }

public interface IGenericService<T>
{
    [OperationContract(Name = "Get{0}")] //This will NOT format properly
    T Get<T>();
}

Опять же, почему? Очевидно, я объявляю здесь конкретный тип Foo, что означает, что IGenericService является IGenericService‹Foo›, поэтому не следует ли форматировать имя OperationContract, поскольку оно ЗНАЕТ тип?


Обновлять:

Я только что вспомнил, почему я был расстроен из-за невозможности использовать общий формат ServiceContract... когда у меня есть реализация службы, я даю ей конкретный тип...

//See! I gave it a concrete type to go by!
[ServiceBehavior(...)]
public class MyService : IGenericService<Foo> { ... }

Я создал Microsoft Connect запрос на это. Пожалуйста, проголосуйте, если вы хотите использовать эту функцию для других атрибутов. http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2327048-enable-generics-for-datamemberattribute-serviceco


person myermian    schedule 28.06.2011    source источник
comment
+1 просто потому, что я не знал, что ты в любом случае можешь это сделать. Если бы мне пришлось угадывать, я бы сказал, что MS реализовала его в двух местах, где общие типы определены и должны быть дифференцированы. Например, у вас не может быть List<string> и List<DateTime>, оба имеют имя контракта данных List, поэтому они должны были сделать это, чтобы заставить WCF работать внутри. Было бы интересно просмотреть код в Reflector или любом другом инструменте и посмотреть, где они это реализовали. Какой бы класс ни читал атрибуты DataContract и DataCollectionContract, он должен отличаться от того, который читает остальные.   -  person CodingWithSpike    schedule 29.06.2011


Ответы (2)


Кажется, это выбор реализации MS. В System.Runtime.Serialization.DataContract имя создается следующим образом:

private static XmlQualifiedName GetDCTypeStableName(Type type, DataContractAttribute dataContractAttribute)
{
  string localName;
  if (dataContractAttribute.IsNameSetExplicit)
  {
    string str = dataContractAttribute.Name;
    if (str == null || str.Length == 0)
    {
       ...
    }
    else
    {
      if (type.IsGenericType && !type.IsGenericTypeDefinition)
        str = DataContract.ExpandGenericParameters(str, type);
      localName = DataContract.EncodeLocalName(str);
    }
  }

Таким образом, он явно создает общее имя. В случае с ServiceContract, это обрабатывается в System.ServiceModel.Description.TypeLoader и System.ServiceModel.Description.NamingHelper и ничего не делает с универсальными типами (по крайней мере, не то, что я вижу).

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

person CodingWithSpike    schedule 28.06.2011
comment
Имеет смысл... команда 1 решает сделать все возможное для именования, а команда 2 не... пойди разберись... добавить общее именование в список пожеланий для следующего WCF. вздох - person myermian; 30.06.2011

Прочитайте это: http://msdn.microsoft.com/en-us/library/ms731045.aspx#Y1254

По сути, кажется, что система именования изначально была разработана без возможности форматирования имен, но в конечном итоге система именования DataContract раздражала достаточно людей (из-за хэша), что они добавили возможность форматирования их имен.

РЕДАКТИРОВАТЬ:

«Однако могут быть причины изменить это имя по умолчанию. Одна из причин — позволить существующему типу обрабатывать данные, которые должны соответствовать существующему контракту данных. Например, существует тип с именем Person, но контракт данных, воплощенный в XML-схема требует, чтобы имя было "Клиент". Контракт может быть выполнен путем установки значения свойства "Клиент".

Вторая причина состоит в том, чтобы разрешить генерацию имен, недопустимых в качестве имен типов. Например, если контракт данных требует имени, которое недопустимо в качестве имени типа, задайте для свойства значение этого запрещенного имени. Например, строка "$value" запрещена в качестве имени типа, но разрешена в качестве значения свойства Name.

Источник: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.name.aspx

Мое предположение, опять же, заключается в том, что такой необходимости изменять имя по умолчанию для других (включая OperationContract, ServiceContract и т. д.) не возникло.

person Alec    schedule 28.06.2011
comment
Я прочитал это. Он объясняет вещи с точки зрения DataContract, но не говорит, почему другие контракты не были исправлены, чтобы разрешить форматирование и дженерики. - person myermian; 29.06.2011