tags:

views:

101

answers:

8
+3  A: 

Sorry, AFAIK it is impossible to do such a conversion without traversing graph in languages I know.

For simple solution ignoring this requirement consider using Automapper (assuming you use .NET; if not, please specify platform you develop on)

elder_george
A: 
var myclients = clients.OfType(typeof(MyClients))

a little LINQ to the rescue :-)

Johannes Rudolph
A: 

Given your dot points, the answer is: No.

Why don't you just create the right objects as you're making the graph?

Noon Silk
A: 

Can't you just cast them when you use the objects instead?

thr
A: 

Casting the more generic object to a more specific one doesn't won't work directly.

You can't cast Client to MyClient but you could cast MyClient to Client.

jitter
+1  A: 

You could create a wrapper class for your graph, which would walk the object graph as needed (possibly with some caching of newly created objects).

Note that this is not casting, but you are simply creating a new instance of your class when needed, something like:

public class InitialGraph : IGraph
{
     IEnumerable<Client> GetClients()
     {
         ...
     }
}

and then you wrap it like this:

public class MyGraph : IGraph
{
     private readonly IGraph _initial;
     public MyGraph(IGraph initial)
     {
         _initial = initial;
     }

     IEnumerable<Client> GetClients()
     {
          foreach (Client c in _initial.GetClients())
              yield return new MyClient(c);
     }
}

Your MyClient instances would be created on access (lazy init).

[Edit]

Actually, since your new graph is supposed to have different objects (not derived from Client), then the GetClients() method could not return IEnumerable<Client>, but:

// note that this class doesn't implement IGraph anymore
public class MyGraph
{
     private readonly IGraph _initial;
     public MyGraph(IGraph initial)
     {
         _initial = initial;
     }

     IEnumerable<MyClient> GetClients()
     {
          foreach (Client c in _initial.GetClients())
              yield return new MyClient(c);
     }
}
Groo
I like the idea behind this solutions. Just to verify shouldn't IEnumerable<Client> GetClients() be IEnumerable<MyClient> GetClients()
John Soer
Hmmm.. While I was writing it, I presumed that MyClient is derived from Client (so that the IGraph interface would be implemented transparently). But you may not need that (I just wrote it as an example). In that case, yes, it would be IEnumerable<MyClient>, but MyGraph and InitialGraph wouldn't share the same interface.
Groo
+1  A: 

Serialization and XSLT might help, but this would involve walking the object graph (probably multiple times).

Gordon Mackie JoanMiro
My current solution I am doing something along this line. The objects by application A are being serialized and placed on a pipe. When application B pulls the data of the pipe and deserialized it I do a quick search and replace to replace Clients with MyClients and Address with MyAddress. However this seems very hackish to me and was hoping that there would be a better solution.
John Soer
+1  A: 

In a comment under your original question, you say:

The reason for the cast is that the object graph starts in application A the object graph gets serialized and passed to appliaction B or application C. Appplication B and C extend the object graph for its own purposes. Application A is not aware of Application B or C or what Application B and C are doing to the object graph. Application B and C are vastly different applications

And yet in the question you say a good solution:

Does not modify the Clients or Address objects

A cast isn't able to add capabilities to an object. The object already has to have those capabilities.

So it sounds like you don't want to change the types, you just want to add extra facilities to those types within certain areas of your solution.

So you need extension methods.

You'd keep the types Client and Address, but add additional facilities via extension methods:

public static class MyExtensions
{
    public static void SendLetter(this Address address, string messageBody)
    {
        // blah
    }
}

This allows you to write:

someClient.Addresses[0].SendLetter("Dear Sir, K THX BAI");

You may need to store extra data along with each Address object. Probably the most convenient off-the-shelf solution to this is to make Address derive from DependencyObject, which allows you to stash extra data, using an instance of DependencyProperty as the key:

public static class MyExtensionsWithData
{
    // declare one of these for each "data slot" you'll be using
    public static readonly DependencyProperty PhoneProperty = 
        RegisterAttached("PhoneNumber", 
                         typeof(string), 
                         typeof(MyExtensionsWithData));

    public static void SetPhoneNumber(this Address address, string phone)
    {
        address.SetValue(PhoneProperty, phone);
    }

    public static string GetPhoneNumber(this Address address)
    {
        return (string)address.GetValue(PhoneProperty);
    }
}

This way, you can effectively add new properties to existing object, and can use them like this:

// set
someClient.Addresses[0].SetPhoneNumber("5550945793847");

// get
string phoneNum = someClient.Addresses[0].GetPhoneNumber();
Daniel Earwicker
This is awesome.
John Soer
I have been thinking about this but this still posses a problem. In the extension example the MyClients object still has a list of Addresses and not a list of MyAddresses
John Soer
It sounds like you've misunderstood something - there is no `MyClients` class. The only classes I wrote were `static` classes, as you have to put extension methods in a static class (the name of which is irrelevant). Note the `this` keyword before the first parameter; that tells the compiler to "attach" the method to object of the same type as that first parameter. The types of all objects (whether clients or address) are unchanged, but they have gained extra capabilities. So it isn't necessary to change the type of anything.
Daniel Earwicker
I wonder if you are clear on how object types work in .NET? You cannot change the type of an object after it is created. For value types (`int`, `bool`, `double`, `byte`, etc), a cast creates a *copy* of the original object. The copy is of the new type, but the original is unchanged. For reference types, there is no copying. A cast creates a new reference of the target type. The reference points to the same original object, and so the cast will fail (throw an exception) if the new reference's type is not already supported by the original object. So casts *never* change the type of an object.
Daniel Earwicker