Se utilizziamo nella nostra soluzione delle custom entities che posizioniamo in un assembly a se stante possiamo ovviamente referenziare lo stesso sia dal progetto che contiene il web service, sia dal progetto client che lo consuma.
Possiamo veicolare queste entità (oggetti) attraverso il web service (rimando a riguardo all'ottimo webcast di Andrea), ma sul client noi non utilizziamo la classe vera e propria che abbiamo definito, ma solo una sorta di mezzo-clone che assomiglia a quella classe.
Quando ho dovuto affrontare il problema sono stato costretto (vista l'urgenza) a cavarmi d'impaccio copiando barbaramente, proprietà per proprietà, tutti i valori. In seguito, parlandone al volo dopo un evento, Andrea mi suggeriva di utilizzare Reflection per risolvere il problema.
Purtroppo anche riguardandomi i suoi 3 webcast sui web services non ho trovato qualche riferimento a questo problema (bisogna dire che le Q&A però sono state tagliate...) ed allora, visto che Reflection era uno di quegli argomenti che non avevo mai avuto modo di affrontare "realmente", ho deciso di scrivermi una funzioncina che cerca semplicemente di copiare i valori delle proprietà e dei campi che trova all'interno della classe. Probabilmente non era proprio quello che intendeva #Andrea quando mi ha detto "devi usare Reflection", e ovviamente immagino che esistano funzioni e/o strumenti molto più completi ed efficaci, ma come "studio" di sicuro mi è servito! Se a qualcun'altro interessa... sono curioso (come sempre) di conoscere le vostre opinioni!
Attenzione: la funzione non è stata testata ed è stata "buttata lì" a scopo didattico! Non credo sia il caso di usarla senza prima verificarne realmente la corretta funzionalità!
Public Shared Function WSEntityCopyTo(ByVal sourceObject As Object, ByVal targetType As Type) As Object
'Scritta da Mario Duzioni
'http://blogs.ugidotnet.org/duz
'http://www.duzioni.com
'Commenti e critiche costruttive sono sempre bene accette
'Rev.0 - 08/06/2005
Dim sourceType As Type = sourceObject.GetType
Dim result As Object = Activator.CreateInstance(targetType)
'Cerco tutti i membri pubblici
Dim destMembers As Reflection.MemberInfo()
Dim newValue As Object
Dim sourceMemberType As Type
Dim targetMemberType As Type
Dim complexMemberType As Boolean
'Recupera tutti i membri
For Each sourceMember As Reflection.MemberInfo In sourceType.GetMembers()
'Cerca solo campi e proprietà
If sourceMember.MemberType = Reflection.MemberTypes.Field Or sourceMember.MemberType = Reflection.MemberTypes.Property Then
'Cerco se esiste lo stesso membro nella destinazione
destMembers = targetType.GetMember(sourceMember.Name)
'Se trova il membro prova a copiare il valore
Select Case destMembers.Length
Case Is = 1
'Ottiene i tipi di sorgente e destinazione
Select Case sourceMember.MemberType
Case Reflection.MemberTypes.Field
sourceMemberType = DirectCast(sourceMember, Reflection.FieldInfo).FieldType
Case Reflection.MemberTypes.Property
sourceMemberType = DirectCast(sourceMember, Reflection.PropertyInfo).PropertyType
End Select
Select Case destMembers(0).MemberType
Case Reflection.MemberTypes.Field
targetMemberType = DirectCast(destMembers(0), Reflection.FieldInfo).FieldType
Case Reflection.MemberTypes.Property
targetMemberType = DirectCast(destMembers(0), Reflection.PropertyInfo).PropertyType
End Select
'Verifica che si tratti di un campo o di una proprietà
If sourceMember.MemberType = Reflection.MemberTypes.Field Or sourceMember.MemberType = Reflection.MemberTypes.Property Then
'Leggo il valore a seconda che sia un campo o una proprietà
Select Case sourceMember.MemberType
Case Reflection.MemberTypes.Field
newValue = DirectCast(sourceMember, Reflection.FieldInfo).GetValue(sourceObject)
Case Reflection.MemberTypes.Property
'Presume che la proprietà non sia indicizzata
newValue = DirectCast(sourceMember, Reflection.PropertyInfo).GetValue(sourceObject, Nothing)
End Select
'Controlla se il tipo del membro è uguale
If Not sourceMemberType Is targetMemberType Then
'SOpporta anche il Null...
If Not newValue Is Nothing Then
'Se non è uguale o è un altro UDT oppure è incompatibile
Try
newValue = ConvertTo(newValue, targetMemberType)
Catch ex As Exception
'Sollevo un eccezione: i due tipi non sono compatibili!
Throw New ArgumentException("The source object type does not match the return type!")
End Try
End If
End If '/Controlla se il tipo del membro è uguale
'Setto il valore a seconda che sia un campo o una proprietà
Select Case destMembers(0).MemberType
Case Reflection.MemberTypes.Field
DirectCast(destMembers(0), Reflection.FieldInfo).SetValue(result, newValue)
Case Reflection.MemberTypes.Property
'Presume che la proprietà non sia indicizzata
DirectCast(destMembers(0), Reflection.PropertyInfo).SetValue(result, newValue, Nothing)
End Select
End If '/Verifica che si tratti di un campo o di una proprietà
Case Is > 1
'Sollevo un eccezione: la copia potrebbe risultare ambigua!
Throw New Exception(String.Format("There are more members named ""{0}"" in the return type", sourceMember.Name))
End Select
End If
Next '/Recupera tutti i membri pubblici
Return result
End Function