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)
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)
var myclients = clients.OfType(typeof(MyClients))
a little LINQ to the rescue :-)
Given your dot points, the answer is: No.
Why don't you just create the right objects as you're making the graph?
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
.
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);
}
}
Serialization and XSLT might help, but this would involve walking the object graph (probably multiple times).
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();