First you add some implicit type operators:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace typeoverridedemostrater { class Class2 { public string string1; public string string2; public string string3; public static implicit operator Class2(Class1 initialData) { return new SuperConverter<Class1, Class2>().Convert(initialData); } public static implicit operator Class2(Class3 initialData) { return new SuperConverter<Class3, Class2>().Convert(initialData); } } }
After you call the converter, you can add whatever specific conversions you need.
(EDIT - as Brooke pointed out, the real version of this was an extension to an existing class, not a class with an internal operator the code above was from the demo project I bashed out to explain the concept to another dev)
Then you use some reflection and linq to do the assignments in a separate class that you can re-use in as many type converters as you like:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace typeoverridedemostrater { class SuperConverterwhere T2 : new() { public T2 Convert(T1 i) { var temp = new T2(); typeof(T1).GetProperties().ToList().Where(a => a.CanWrite).ToList(). ForEach(b => { var z = temp.GetType().GetProperty(b.Name); if (z != null) z.SetValue(temp, b.GetValue(i, null), null); }); typeof(T1).GetFields().ToList().ToList(). ForEach(b => { var z = temp.GetType().GetField(b.Name); if (z != null) z.SetValue(temp, b.GetValue(i)); }); return temp; } } }
Obviously this only works in some cases, and if your types do not match precisely you would have to make it a little more complex by checking for compatible types, or handling failure more gracefully, but it can save a ton of time in some cases.
Your solution doesn't abide by the rules stated in your problem. "neither API can be modded at the moment" yet you're adding implicit operators to the API, that counts as "modded".
ReplyDeleteThere are excellent tools in existence to do this already, which are likely much faster due to the fact that they generate the mapping code in MSIL when you create the map, then just call it when mapping objects. Using reflection to do this is going to be far slower. AutoMapper and ValueInjector are two examples of Libraries to do this.
This seems like an example how not to use operator overloading. If anything an extension method would be best.
The right answer is to give them a common base or interface, second best would be MSIL or dynamic tricks.
ReplyDeleteThis solution has a significant perf penalty and is a questionable use of operator overloading if you are a stickler for that on a temporary hack, but it does not mod the signature outside the WCF or require any of the players to add a new reference to a third party tool that would require approval.
The actual use of this was as an extension and I will edit accordingly, thanks for pointing this out.
I should probably also point out if it is not clear that it assumes a lot about the objects similarity and cannot do readonly collection property item adds, indexed properties and a few other things at all. It is not high performance and under load will get worse. Pretty much don't do this anywhere very important and don't do anything remotely like it except as a temporary measure.
ReplyDeleteGiving them a common base or interface assumes you can modify both apis, and if that's the case it's an entirely different problem space. If the goal is either A) to work with two disperate apis which you don't control or B) to eliminate coupling where it shouldn't exist, then the mapper pattern is the correct approach.
ReplyDeleteThis was the sort of case of where the dependency should exist, but somebody overlooked it and we needed to get something up for a demo.
ReplyDeleteThere are definitely some nice things you can do in this area if you actually have a case where you need this long-term and you need top performance. this case had neither requirement and this has the advantage of not requiring a pass w/the full project team to get approval for more 3rd party code.
check out the next couple of posts to see what the more advanced methods might look like
ReplyDelete