I have a quite big class A with lots of members, and i have a quite big class B that can be built when having an A object. An A object can be built when having a B object. I need both of them, as A is a kind of ViewModel, which has validation and B is a graphical description, which can be plotted easily.
How to do this conversion?
here is an example, to illustrate what i want to do:
class A
{
string s;
string t;
string u;
string v;
enum a;
enum b;
enum c;
enum d;
enum e;
Dictionary<enum, string> dict;
}
class B
{
string someString; // is essentially A.a + A.b + A.c + A.s with some rules.
int someValue; // is essentially dict.TryGetValue(enum.Entry);
string anotherString;
// ... and lots of others
}
Of course it is simple to do some mapping, and build up a B object, and it is not very hard to write plain B => A mapping by inverting the rules of building A => B
So the questions are:
- Are there any well known patterns to achieve that?
- Is there a default C# way of doing such things?
Writing down plain something like that seems not to fit, it ends up in hundreds of lines of code.
I thought about some kind of converter classes for the parts, like SomeStringConverter, SomeValueConverter, ...
- How can i abstract the needed members of A together with the rules to do the mapping.
- How can i write those rules to have the easiest possible way of doing A => B and B => A.
Edit: Pattern here is meant as "Best practises" and not as "GoF design patterns"
SomeString in the B class is some kind of "selector", it selects drawing options, it is always 25 characters long and the enums in class A choose those characters, but not 1 on 1 in most cases.
Lets say for example: A.a = "Filled", A.b = "SingleCoordinate", A.c = "DrawHints" will result in something like SomeString =
"Y**D***RR****---***---***"
i.e. the combination is important to get such an string, but from the combiniation you can derive the enums that have to be set in an A object.
Edit2:
I'm especially interested in ways of using my mapping rules for both ways, i.e.
A.a = "Filled" combined with A.b = "SingleCoordinate" combinded with A.c = "DrawHints" will result in (partial string) "Y**D***RR"
, and that partial string also means that
A.a has to be set to "Filled" and so on.
It depends on what you mean by pattern. The
Decorator
orAdapter
patterns come to mind, but neither is meant for wholesale mapping of types to different types.No, there isn't. But libraries like Automapper sure make life easier.
A couple thoughts:
A) Change B into an interface which A implements. This would allow you to "map" B's properties directly to A's properties without having to recreate them. In cases where B has a property that A is not supposed to have (or a property which combines several of A's), you can set the access modifier to private* - meaning the property will only be visible through the interface (so as not to confuse or clutter implementations of A).
B) Use a pseudo adapter/wrapper pattern. B, given a constructor parameter of type A, can refer back to A's properties, etc. Where B differs, it can implement its own logic.
Mapping between two complex objects requires some complex thinking. There will always be special cases, side effects and choices requiring thought and balancing of pros and cons. (For example, converting between a string and an int introduces all kinds of question - what to do with the thousand's separator, how to handle different cultures, etc.) From reading your specific circumstances, I do not see an easy or quick way to handle the mapping - you'll have on a method based on all the factors involved, probably too many to post here.
EDIT: * I should note that this is what I've done in several VB projects. I assume this is legal in C#, but I've not tried it.
Sounds to me like A is more of the Data Model and B is more of the View Model. I don't think there's a generally accepted "pattern" for this kind of instance—mainly because the reasons behind this kind of pairing vary widely and the best pattern is heavily dependent on intended use.
That said, since they're so tightly tied together, I'd tend to make one class subordinate to the other. In this case, since A is more straightforward, I'd probably use A as the data container for B. i.e. Have a private member A as a field in class B and all the properties in class B reference class A directly—updating properties in A rather than having their own private fields behind. You could then have a public property on class B that exposes the private member of class A if needed. I'd probably keep that read-only, but that's probably not really important (depending on your use of class B and any possible bound relationships). To go the other way, I'd then create a constructor on class B that accepts class A as a parameter. The passed value of A would then be assigned to the private class A member on class B.
The upshot of all that is to maintain class A's ignorance of class B—which becomes useful if you have a true use case for a ViewModel situation. If you determine that class A is the truer ViewModel in your needs, then reverse the above so that class B is the one ignorant of class A.
Factory + possibly Facade
You want to coordinate building a B from an A or an A from a B. This argues that you need complex logic to do so.
To build B from A, either implement as a static method on B (Factory), or create a new class C that inherits from B, and takes an A as argument to its constructor (Facade).
Factory: http://en.wikipedia.org/wiki/Factory_method_pattern (Not an exact match for your situation)
Facade: http://en.wikipedia.org/wiki/Design_Pattern_-_Facade (not an exact match either)
What I have done to solve this problem:
Wrote a BiMap (with the help of older SOs on that issue).
Inserted the Mapping into it (all value combinations in Key, the resulting key in the "Value", together with a BitArray which specifies the indices of the string that are defined by that mapping.
Wrote some code to calculate a resulting overall string from it, as the mapping will just give partial strings.
The one-to-one mappings were trivial.
That way I could use the mappings in both ways. Given a string, I still have a quite expensive search (as I have to compute the stored string utilizing the BitArray as a mask)
At the moment it seems to work very good, but I'm not finished yet.
Thank you all for your very good ideas and approaches! Perhaps AutoMapper can do this, but I do not have much time at the moment to read and try out a new technology.
If anybody can provide some relevant examples on how to do this on Automapper, I will accept it as an answer (as I already love AutoMapper).
Examples like lets say: 3 enums with 5 values to one fixed length string one fixed length string to 3 enum with 5 values (the reverse of the above).
as an example:
Can Automapper achieve such things?