Reputation: 4701
I would like to map 2 objects but I don't want to rely on 3rd party tools - the reason is to help me get a better understanding of what those 3rd party tools may do.
I have an interface, which has string
Foo
and bool
Bar
public interface ITest
{
string Foo { get; set; }
bool Bar { get; set; }
}
My first class, called A
implements ITest
public class A : ITest
{
public string Foo { get; set; }
public bool Bar { get; set; }
}
And finally, Class B
also implements ITest but has an additional property
public class B : ITest
{
public string Foo { get; set; }
public bool Bar { get; set; }
public int Other { get; set; }
}
Since both classes share a common interface, how can I cast one to the other?
var a = new A();
var b = new B();
a= b as A; //does not work but this would be ideal
I don't want to Map by explicitly stating the names of the properties.
As such, having (where the B constructor maps) is also not ideal
var a = new A();
var b = new B(a); //not desired
Is this possible? It would mean that only the properties that were defined in the interface would be copied across.
Answers like C# map two complex objects are not ideal as I have to explicitly state the properties.
Upvotes: 0
Views: 929
Reputation: 734
You can use reflection to automatically detect properties and map their values.
private static T GetMappedObject<T>(object source)
{
var output = Activator.CreateInstance(typeof(T));
var sourceType = source.GetType();
foreach (var outputProperty in typeof(T).GetProperties())
{
if (sourceType.GetProperty(outputProperty.Name) is PropertyInfo sourceProperty)
{
var value = sourceProperty.GetValue(source);
outputProperty.SetValue(output, value);
}
}
return (T)output;
}
You can then call this method like var b = GetMappedObject<B>(a);
.
Note that the above snippet does not check whether the value on the source object can actually be mapped to the output property, and it does require objects of type T
to define a parameterless constructor.
As someone pointed out in the comments, if not for the educational nature of your question, it is still recommended to use a proven 3rd party tool like AutoMapper where you can for production code.
Upvotes: 2
Reputation: 9209
Both classes implement ITest
interface BUT class B
also has an extra property which prevents you from casting between the A
and B
.
You can however have functions that handle ITest
, but treat them differently e.g.
public void SaveDataFunction(ITest param)
{
if (param is A)
{
SaveDataTypeA((A)param);
}
else if (param is B)
{
SaveDataTypeB((B)param);
}
}
private void SaveDataTypeA(A value)
{
}
private void SaveDataTypeB(B value)
{
}
Upvotes: 0
Reputation: 9824
There is no implicit conversion between A
and B
. You can fit both of them in variables of type ITest
, but that is where the automatics end. C#/.NET is very conserviative with implicit conversions.
And if your example would work, it would also have to work between System.String
and System.Windows.Forms.Form
as they both inherit from Object
. Every Class in .NET implicitly or explicitly inherits from Object, so that would be a nightmare.
What you need to do is either:
A(ITest initializeFrom)
Upvotes: 2
Reputation: 39966
You can use explicit operator
, so something like this maybe what you are looking for:
public class A : ITest
{
public string Foo { get; set; }
public bool Bar { get; set; }
public static explicit operator A(B v)
{
return new A { Bar = v.Bar, Foo = v.Foo };
}
}
And then use casting instead:
a = (A)b;
Upvotes: 0
Reputation: 2185
You can use json for this. We do this all the time to cast DataTable into a model.
You Serialize the first model and Deserialize it into the other one. Doing it this way, only the fields that are in common are touched.
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
string serializedObject = JsonConvert.SerializeObject(A, deserializeSettings);
B b = JsonConvert.DeserializeObject<B>(serializedObject);
Upvotes: 0
Reputation: 14191
You have at least 2 options.
Either cast to the interface ITest
: b as ITest
Make B
extend A
. This way casting b to A is safe.
Upvotes: 0