La soluzione più immediata sarebbe quella di avere die metodi, uno per la persona fisica che stampa nome e cognome e l'altra che stampa la ragione sociale. Sebbene questo sia un caso del tutto banale, che succederebbe se le opzioni fossero 10, 20 o di più ancora ? Sarebbe impraticabile.

L'alternativa consiste nell'utilizzare un elemento di scelta (choice). Immaginiamo quindi di avere due classi:

public class PersonaFisica
{
 public string Nome;
 public string Cognome;
}

public class PersonaGiuridica
{
 public string RagioneSociale;
}

possiamo mappare le classi su un'unica proprietà:

[XmlType(Namespace="urn:peway:datatypes")]
public class Contatto
{
 public string CodiceFiscale;

 [XmlIgnore()]
 public TipoPersona Tipo;

 [XmlChoiceIdentifier("Tipo")]
 [XmlElement("PersonaFisica", typeof(PersonaFisica))]
 [XmlElement("PersonaGiuridica", typeof(PersonaGiuridica))]
 public object Persona;
}

dove TipoPersona è un enumerato:

public enum TipoPersona
{
 PersonaFisica,
 PersonaGiuridica
}

in questo modo, stiamo dicendo al serializzatore XML che la proprietà Persona può essere sia PersonaGiuridica che PersonaFisica. L'attributo XmlChoiceIdentifierAttrbute è usato semplicemente per informare quale classe stiamo usando attraverso un enumerato. Il deserializzatore, quando arriva il messaggio SOAP andrà a verificare di che tipo è Persona e lo mapperà sulla classe corrispondente.

Diventa quiandi abbastanza semplice stampare il nominativo in base al valore contenuto dall'enumerato:

[WebService(Namespace="urn:peway:services")]
public class Contatti
{
 [WebMethod]
 public string StampaNominativo(Contatto contatto)
 {
  switch(contatto.Tipo)
  {
   case TipoPersona.PersonaFisica:
    PersonaFisica pf = (PersonaFisica)contatto.Persona;
    return string.Concat(pf.Nome, " ", pf.Cognome);
   case TipoPersona.PersonaGiuridica:
    PersonaGiuridica pg = (PersonaGiuridica)contatto.Persona;
    return pg.RagioneSociale;
   default:
    return "Nessuna persona identificabile";
  }
 }
}