Pergunta

Eu tenho um tipo, vamos chamá-lo Data<TKey>. Eu também tenho um contrato de serviço WCF que aceita um tipo (vamos chamá-lo Wrapper) com uma propriedade do tipo Object (por razões que eu não vou entrar, isso não é opcional).

[DataContract]
public class Data<TKey> { ... }

[DataContract]
public class Wrapper
{
    [DataMember]
    public object DataItem { get; set; }
}

Agora estou enviando duas classes IntData e LongData:

[DataContract]
public class IntData : Data<int> { /*empty*/ }

[DataContract]
public class LongData : Data<long> { /*empty*/ }

Eles estão ambos configurados nos tipos conhecidos config. A assemelha configuração algo como isto:

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="Wrapper, TheirAssembly">
          <knownType type="IntData, MyAssembly"/>
          <knownType type="LongData, MyAssembly"/>
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

Neste ponto, tudo funciona bem.

Mas estou prestes a adicionar um terceiro tipo e eu não gosto de ter o desnecessário, vazio classes de .NET IntData e LongData. Eles só existem porque ...

Eu não sei como especificar tipos genéricos na configuração WCF!

Eu quero fazer algo assim, mas não sei a sintaxe exata.

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="Wrapper, TheirAssembly">
          <!-- this syntax is wrong -->
          <knownType type="Data{System.Int32}, MyAssembly"/>
          <knownType type="Data{System.Int64}, MyAssembly"/>
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

O que é a sintaxe correta para isso?

(Nota também que eu não posso colocar [KnownType(...)] atributos de Wrapper como não é meu tipo. Config parece ser o único caminho.)

Editar

resposta

@ do baretta funcionou muito bem. Note, porém, que, inicialmente, eu recebi este erro:

Type 'MyAssembly.Data`1 [System.Int64]' não pode ser adicionada à lista de tipos conhecidos desde outro tipo 'MyAssembly.Data`1 [System.Int32]' com o mesmo nome contrato de dados ' http://www.mycompany.com/MyAssembly:Data ' já está presente.

Eu não mencionou isso na pergunta original, mas meu tipo tem um nome de contrato de dados explícito. Algo parecido com isto:

[DataContract(Name = "Data")]
public class Data<TKey> { ... }

O erro ocorreu acima até que eu removi o valor da propriedade Name do atributo. Espero que ajude alguém com muito. Eu não sei o formato funciona neste cenário. Estes não fez:

[DataContract(Name = "Data\`1")]
[DataContract(Name = "Data{TKey}")]

Alguém sabe como fazer isso?

EDIT 2

Obrigado novamente para @baretta que apontaram que a sintaxe correta é de fato:

[DataContract(Name = "Data{0}")]
Foi útil?

Solução

Um tipo genérico é instanciável de uma string, se a cadeia segue esse padrão: nome da classe seguido por um caractere "`", seguido do número de parâmetros de tipo (neste caso é 1), seguido pelos parâmetros de tipo fechado dentro "[]", e usando vírgula como tipo de parâmetro separador .

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
        <add type="Wrapper, TheirAssembly">
          <!-- this syntax is all good -->
          <knownType type="Data`1[System.Int32], MyAssembly"/>
          <knownType type="Data`1[System.Int64], MyAssembly"/>
        </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

Edit:. Eu poderia também acrescentar que se as necessidades de informação de montagem deve ser especificado para os parâmetros de tipo (althoug não é o caso para o material em mscorlib), então aninhados "[]" é usado

<knownType type="Data`1[[System.Int32, mscorlib]], MyAssembly"/>

Edit:. Você pode personalizar nomes de tipos genéricos em contratos de dados, usando o padrão de formato de cadeia

[DataContract(Name = "Data{0}")]
public class Data<TKey>
{...}

Por padrão, o nome gerado para a dados tipo é algo como "DataOfInt32HJ67AK7Y", onde "HJ67AK7Y" é um hash gerado a partir da cadeia "urn: default", ou o namespace de sua classe, se tiver algum. Mas "Dados {0}" iria dar-lhe o nome de "DataInt32".

aqui . Ter um olhar para os "Personalização de dados Nomes contrato para tipos genéricos" parte de baixo da página.

Outras dicas

A partir aqui ...

Conhecido tipos também pode ser definida como na configuração mostrado abaixo.

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
         <add type="MyCompany.Library.Shape`1,
              MyAssembly, Version=2.0.0.0, Culture=neutral,
              PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
            <knownType type="MyCompany.Library.Circle`1,
                       MyAssembly, Version=2.0.0.0, Culture=neutral,
                       PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
                    <parameter index="0"/>
            </knownType>
         </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

Os especifica configuração acima que o parâmetro genérico para Circle é o mesmo que o parâmetro genérico para o tipo declarado Shape. A configuração permite a definição de tipo conhecido de complexidade arbitrária. Por exemplo, se ela é necessária para definir Círculo > como o tipo conhecido de Forma (é claro que isso é puramente acadêmico) que pode ser feito como segue.

<configuration>
  <system.runtime.serialization>
    <dataContractSerializer>
      <declaredTypes>
         <add type="MyCompany.Library.Shape`1,
              MyAssembly, Version=2.0.0.0, Culture=neutral,
              PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
            <knownType type="MyCompany.Library.Circle`1,
                       MyAssembly, Version=2.0.0.0, Culture=neutral,
                       PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
                   <parameter type="System.Collections.Generic.Dictionary`2">
                      <parameter type="System.String"/>
                      <parameter index="0"/>
                   </parameter>                
            </knownType>
         </add>
      </declaredTypes>
    </dataContractSerializer>
  </system.runtime.serialization>
</configuration>

Observe o elemento de utilização de configuração “Parâmetro” com ‘tipo’ os atributos e ‘index’.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top