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
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.
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.