WCF Generics - Why do DataContract and CollectionD

2019-07-11 04:57发布

问题:

Basically as the title says:

[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>();
}

So, there ya have it... what works and doesn't work... but the question is... why? Obviously .NET is able to create a concrete type and format the name when using a DataContract and CollectionDataContract and stating the type (i.e. GenericItem<Foo> or SpecialCollection<Foo>. So why not have the DataMember also be able to format as well?

The ServiceContract/OperationContract I can sort of understand in the manner it's left in above (sorta), but what I don't understand is when you give it a concrete type the operations still won't work properly:

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

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

Again, why? Obviously I'm declaring a concrete type of Foo here which means the IGenericService is an IGenericService<Foo> so shouldn't the OperationContract name be formatted since it KNOWS the type?


Update:

I just remembered why I was upset about not being able to use a Generically formatted ServiceContract... when I have the implement the service I'm giving it a concrete type...

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

I created a Microsoft Connect request for this. Please upvote it if you want this feature for the other attributes. http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2327048-enable-generics-for-datamemberattribute-serviceco

回答1:

This seems to be an implementation choice by MS. In System.Runtime.Serialization.DataContract it builds up the name by doing:

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);
    }
  }

So it explicitly builds out the generic name. In the case of ServiceContract stuff, that is handled in System.ServiceModel.Description.TypeLoader and System.ServiceModel.Description.NamingHelper, and does not do anything with generic types (at last not that I am seeing).

So I'm guessing since these contracts stem from different assemblies and namespaces, they may have been implemented by different teams to begin with.



回答2:

Read this: http://msdn.microsoft.com/en-us/library/ms731045.aspx#Y1254

Basically, it seems like the naming system was originally designed without being able to format the names, but eventually the DataContract naming system annoyed enough people (because of the hash) that they added the ability to format the names of them.

EDIT:

"However, there may be reasons to change this default name. One reason is to allow an existing type to process data that must conform to an existing data contract. For example, there exists a type named Person but the data contract, embodied in an XML schema, requires that the name be Customer. The contract can be satisfied by setting the property value to Customer.

A second reason is to allow the generation of names that are invalid as type names. For example, if a data contract demands a name that is not allowable as a type name, set the property value to that disallowed name. For instance, the string "$value" is disallowed as a type name but is allowed as a Name property value."

Source: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractattribute.name.aspx

My guess, again, is that no such need to change the default name of the others (including OperationContract, ServiceContract, etc.) has come up.