views:

145

answers:

6

I'm using a 3rd party's set of webservices, and I've hit a small snag. Before I manually make a method copying each property from the source to the destination, I thought I'd ask here for a better solution.

I've got 2 objects, one of type Customer.CustomerParty and one of type Appointment.CustomerParty. The CustomerParty objects are actually property and sub-oject exactly the same. But I can't cast from 1 to the other.

So, I need to find a certain person from the webservice. I can do that by calling Customer.FindCustomer(customerID) and it returns a Customer.CustomerParty object.

I need to take that person that I found and then use them a few lines down in a "CreateAppointment" request. Appointment.CreateAppointment takes an appointment object, and the appointment object contains a CustomerParty object.

However, the CustomerParty object it wants is really Appointment.CustomerParty. I've got a Customer.CustomerParty.

See what I mean? Any suggestions?

+2  A: 

This scenario is common when writing domain patterns. You essentially need to write a domain translator between the two objects. You can do this several ways, but I recommend having an overridden constructor (or a static method) in the target type that takes the service type and performs the mapping. Since they are two CLR types, you cannot directly cast from one to the other. You need to copy member-by-member.

public class ClientType
{
    public string FieldOne { get; set; }
    public string FieldTwo { get; set; }

    public ClientType()
    {
    }

    public ClientType( ServiceType serviceType )
    {
        this.FieldOne = serviceType.FieldOne;
        this.FieldTwo = serviceType.FieldTwo;
    }
}

Or

public static class DomainTranslator
{
    public static ServiceType Translate( ClientType type )
    {
        return new ServiceType { FieldOne = type.FieldOne, FieldTwo = type.FieldTwo };
    }
}
j0rd4n
I think I'm going to have to go this route. :( Thanks for the answer. Unfortunately StackOverflow won't let me upvote your posts. OpenID doesn't work on StackOverflow from my work computer -- other openid sites do, just not StackOverlow.
Matt
@Matt: You should be aware that there are simple ways like dynamic methods that don't require you to write the mapping code yourself.
0xA3
You can override the explicit cast as well.
Aren
+1  A: 

I'm using a 3rd party's set of webservices...

Assuming you can't modify the classes, I'm not aware of any way you can change the casting behavior. At least, no way that isn't far, far more complicated than just writing a CustomerToAppointmentPartyTranslator() mapping function... :)

Assuming you're on a recent version of C# (3.5, I believe?), this might be a good candidate for an extension method.

djacobson
+6  A: 

Why don't you use AutoMapper? Then you can do:

TheirCustomerPartyClass source = WebService.ItsPartyTime();

YourCustomerPartyClass converted = 
    Mapper.Map<TheirCustomerPartyClass, YourCustomerPartyClass>(source);

TheirCustomerPartyClass original = 
    Mapper.Map<YourCustomerPartyClass, TheirCustomerPartyClass>(converted);

As long as the properties are identical, you can create a really simple map like this:

Mapper.CreateMap<TheirCustomerPartyClass, YourCustomerPartyClass>();
Mapper.CreateMap<YourCustomerPartyClass, TheirCustomerPartyClass>();
GenericTypeTea
I'll see if we can add this into our project. Not sure if it is worth the overhead at this point, but thanks for the suggestion. I'm sure it would solve my problem. Unfortunately StackOverflow won't let me upvote your posts. OpenID doesn't work on StackOverflow from my work computer -- other openid sites do, just not StackOverlow.
Matt
@Matt - There's almost no overhead. AutoMapper is pretty lightweight. Definitely worth a go.
GenericTypeTea
A: 

Two classes with exactly the same signature, in two different namespaces, are two different classes. You will not be able to implicitly convert between them if they do not explicitly state how they can be converted from one to the other using implicit or explicit operators.

There are some things you may be able to do with serialization. WCF DataContract classes on one side do not have to be the exact same type as the DataContract on the other side; they just have to have the same signature and be decorated identically. If this is true for your two objects, you can use a DataContractSerializer to "convert" the types through their DataContract decoration.

If you have control over the implementation of one class or the other, you can also define an implicit or explicit operator that will define how the other class can be converted to yours. This will probably simply return a new reference of a deep copy of the other object in your type. Because this is the case, I would define it as explicit, to make sure the conversion is only performed when you NEED it (it will be used in cases when you explicitly cast, such as myAppCustomer = (Appointment.CustomerParty)myCustCustomer;).

Even if you don't control either class, you can write an extension method, or a third class, that will perform this conversion.

KeithS
A: 

Hi,

Have you looked at adding a conversion operator to one of the domain classes to define an explicit cast. See the msdn documentation here.

Enjoy!

Doug
A: 

A simple and very fast way of mapping the types is using the PropertyCopy<TTarget>.CopyFrom<TSource>(TSource source) method from the MiscUtil library as described here:

using MiscUtil.Reflection;

class A
{
    public int Foo { get; set; }
}

class B
{
    public int Foo { get; set; }
}

class Program
{
    static void Main()
    {
        A a = new A();
        a.Foo = 17;
        B b = PropertyCopy<B>.CopyFrom(a);

        bool success = b.Foo == 17; // success is true;
    }
}
0xA3