Assume that I have 2 classes: A & B
public class A
{
public string p1{get;set};
public string p2{get;set};
}
public class B : A
{
public string p3{get;set};
}
I have an object 'a' from class A, I want to create an object 'b' from class B which copy all property values from 'a'. Normally, I must do like following:
B b = new B();
b.p1 = a.p1;
b.p2 = a.p2;
With this solution, I must lose many codes if I must assign manually. Is there any solutions? Thanks.
You can look into using something like http://automapper.codeplex.com/ that will automatically map properties from a source object into a destination object for you using predefined rules.
then its as simple as configuring once like so:
Mapper.CreateMap<A, B>();
And creating your new object like this:
B b = Mapper.Map<B>(a);
You can write your own hydrator, if you like to, using reflection, so it will compare object properties, names and types.
Or you can use automapper as mentioned in another answer.
The third solution is to internalize adaption in code. Since "B" knows about "A", do
public class B : A
{
public string p3{get;set};
public void Hydrate{A a}
{
this.p1 = a.p1;
this.p2 = a.p2;
}
}
Then your code will be like this
B b = new B();
b.Hydrate(a);
Related
I have these classes
class Start
{
public List<Base> list { get; set; }
public Start()
{
list = new List<Base>();
}
}
public abstract class Base
{
public int a { get; set; }
}
class B : Base
{
public int b;
public B(int a, int b) { this.a = a; this.b = b; }
}
class C : Base
{
public int c;
public C(int a, int c) { this.a = a; this.c = c; }
}
I want list property of class Start to hold instances of class B or instances of class C (not both together, but it may hold the same type of any of B or C)
If possible, I don't want to use Generics
In C#, This is possible:
List<Object> lst = new List<Object>();
lst.Add(1);
list.Add("Text");
Console.WriteLine("{0} {1}", lst[0], lst[1]);
I don't understand why I can't make a similar behavior here:
Start s = new Start();
B b = new B(1, 2);
s.list.Add(b);
Console.WriteLine(s.list[0].a); //works
Console.WriteLine(s.list[0].b); //doesn't work
The difference between the two snippets is that in the first one you are not accessing any type-specific information (fields/properties/methods), i.e. something like the following will not compile too:
List<Object> lst = new List<Object>();
lst.Add(1);
list.Add("Text");
// will not compile despite string having Length property:
Console.WriteLine("{0} {1}", lst[0], lst[1].Length);
a is common property declared in Base class, so it is available for every child of Base, if you want to access child specific properties you need to type test/cast :
Start s = new Start();
B b = new B(1, 2);
s.list.Add(b);
Console.WriteLine(s.list[0].a); //works
if(s.list[0] is B b)
{
Console.WriteLine(b.b);
}
or make Start generic:
class Start<T> where T: Base
{
public List<T> list { get; set; }
public Start()
{
list = new List<T>();
}
}
var s = new Start<B>();
s.list.Add(new B(1, 2));
Console.WriteLine(s.list[0].b);
P.S.
Note that overriding ToString in Base, B and A will make Console.WriteLine("{0}", s.list[0]); "work":
class B : Base
{
// ...
public override string ToString() => return $"B(A: {a} B: {b})";
}
class C : Base
{
// ...
public override string ToString() => return $"C(A: {a} B: {c})";
}
Start s = new Start();
B b = new B(1, 2);
s.list.Add(b);
s.list.Add(new C(4, 2));
Console.WriteLine("{0} {1}", s.list[0], s.list[1]); // prints "B(A: 1 B: 2) C(A: 4 B: 2)"
So possibly you can introduce some method in Base which will allow you to use List<Base> (hard to tell without knowing actual use case).
The List<Object> example is possible because both int and string inherit from Object, which provides a ToString() method that is called implicitly on the line that writes the output. That is, no members of either the int or string types are used in that example that are specific to their own types.
You might accomplish what you need without generics by adding an interface that both B and C can implement, since both the b and c properties are compatible (they are both ints). However, this is clearly a contrived example, and I expect the real code is more complicated. In that case, generics are likely your best option.
because all Base objects dont have 'b' fields
you need to test to see if list[0] is an instance of 'B' and then cast it to a B
if (list[0] is B )
{
Console.WriteLine(((B)(list[0]).b);
}
Based on the comments underneath the question, perhaps a combination of both a non-generic interface and a generic Start class could work in this scenario.
The non-generic base interface for the generic Start class would declare a get-only List property as IReadOnlyList<Base>. IReadOnlyList is co-variant, allowing to return different List<T> instances where T is a concrete derived type from Base.
public interface IStart
{
IReadOnlyList<Base> List { get; }
}
The generic Start<TBase> class implements IStart, puts the IStart.List property in an explicit interface declaration and declares its own List property that is typed as List<TBase>.
public class Start<TBase> : IStart where TBase : Base
{
public List<TBase> List { get; set; }
IReadOnlyList<Base> IStart.List => this.List;
public Start()
{
List = new List<TBase>();
}
}
Note that both the explicit interface implementation of IStart.List and Start<TBase>'s own List property return the same List<TBase> instance.
This setup makes the following things possible (or impossible, see the code comments):
var startC = new Start<C>();
startC.List.Add(new C()); // this works, of course it works
startC.List.Add(new B()); // The compiler will NOT allow this
IStart SomeMethodProducingAStart()
{
if (someCondition)
return new Start<B>();
else
return new Start<C>();
}
void SomeMethodConsumingAStart(IStart start)
{
if (start is Start<B> startWithBs)
{
// do stuff with startWithBs...
Console.WriteLine(startWithBs.List[0].a);
Console.WriteLine(startWithBs.List[0].b);
}
else if (start is Start<C> startWithCs)
{
// do stuff with startWithCs...
Console.WriteLine(startWithCs.List[0].a);
Console.WriteLine(startWithCs.List[0].c);
}
// if you don't care about the members specific to either B or C,
// just do this
Console.WriteLine(start.List[0].a);
// since start can be any Start<T>
// the following is denied by the compiler
// simply by virtue of IStart.List being an IReadOnlyList
start.List.Add(new C()); // no can do!
}
Whether this approach fits your application scenario well is for you to determine, but it's an approach that tries to avoid granular pattern matching on individual list items and aims at simplifying working with Start instances once they have been pattern-matched/cast to the correct Start<TBase> type.
I'm trying to convert some anonymous type back to its original strong type class.
I have some legacy code (which I cannot touch) which create an anonymous class:
public class Cat : FooId
{
public int Id { get; set; }
public string Name { get; set; }
}
var result = new
{
Id = Mapper.Map<TFooId>(someCat)
};
NOTE: I've tried to make this fake class and interface similar to my code.
This then gives me:
result.GetType().ToString() : <>f__AnonymousType1``1[MyProject.Cat]
From here, I'm not sure how to convert this back to a MyProject.Cat instance?
I've tried (and fails):
(MyProject.Cat)result
(dynamic)result
but both fail. The dynamic doesn't throw an error ... but I can't access any properties in it.
C# is a statically typed language, and those two types are not in any way related to one another. Unless you're able to modify the code which defines those types, the way you'd convert from one to the other would be to create a new instance of the target type and populate it from the source object.
For example:
var resultCat = new Cat { Id = result.Id };
Edit: From comments it looks like it may be possible that the Id property on the result object may be an instance of Cat or some other object? You're going to need to do some debugging to find out what your types are.
But the overall concept doesn't really change. If you have an instance of Cat in your results then you can use that instance. If you don't then in order to create one you'd need to create a new instance and populate it with the data you have. Even if two types are intuitively or semantically similar, they are different types.
It's true what David said with regard to the fact that C# is a statically-typed language and that the new instance should be populated from the source the way he suggested.
However, there are work-arounds (though less performant) for that, such as reflection.
Consider you have a console app where you have defined ObjectExtensions as follows:
public static class ObjectExtensions
{
public static TOut Map<TOut>(this object #in)
where TOut : new()
{
TOut #out = new TOut();
if (#in?.GetType() is Type tin)
{
Type tout = typeof(TOut);
foreach ((PropertyInfo pout, PropertyInfo pin) in tout.GetProperties().Join(tin.GetProperties(), pi => pi.Name, pi => pi.Name, (pout, pin) => (pout, pin)))
{
pout.SetValue(#out, pin.GetValue(#in));
}
}
return #out;
}
}
And Class1 as follows:
public class Class1
{
public string A { get; set; } = "A";
public string B { get; set; } = "B";
public string C { get; set; } = "C";
public override string ToString()
{
return $"{{A={A}, B={B}, C={C}}}";
}
}
You will be able to map your anonymous type back to its original strongly-typed class like this:
Console.WriteLine(new { A = "Anonymous A", B = "Anonymous B", C = "Anonymous C" }.Map<Class1>());
Therefore the bloc above should show the following output:
{A=Anonymous A, B=Anonymous B, C=Anonymous C}
In this case, of course, I have assumed that Class1 (Cat in your example) must have a public parameterless constructor. That may not always be the case. There are more sophisticated scenarios of course that might involve other techniques for creating the object such as cloning or dependency injection. Just saying that the idea of yours is possible.
I have two Classes that derive from a mutual class A, which contains some properties (mainly stings and integers). Class B is a different class containing additional properties. More precisely,
public class A1 : A {
private B _bee;
public B Bee {
get { return _bee;}
set { _bee = value;}
}
}
public class A2 : A {
private List<B> _beeList;
public List<B> BeeList {
get { return _beeList;}
set { _beeList = value;}
}
}
Now, given an instance of A1, how can I make an instance of A2 containing the same information (i.e., the properties in the 'A' part, and the instance of 'B'). I tried the following - I wished it'd work, but knew it wouldn't... - (Let me call my instance of A1 resp. A2 by 'one' resp. 'two'):
A _a = (A)one; // This obv works
B _b = one.Bee;
A2 _a2 = (A2)_a; // Threw away the Bee - information, so should work imo
_a2.BeeList.Add(_b);
So how do I do this without populating all properties in A by hand?
using System.Reflection;
private void Convert(A1 _a1, A2 _a2)
{
foreach(PropertyInfo pi in typeof(A).GetProperties())
{
pi.SetValue(_a2,
pi.GetValue(_a1, null)
, null);
}
_a2.BeeList.Add(_a1.Bee);
}
this seemed to work for me
try using automapper.
automapper enables you to copy properties of a class to another class without writing much code.
ex:
Mapper.CreateMap<X, Y>();
Y y = Mapper.Map<X, Y>(x);
Automapper configuration would look like this:
Mapper.CreateMap<A1, A2>()
.ForMember(a2 => a2.BeeList, ctx => ctx.MapFrom(a1 => new List<B>{a1.Bee}));
A a1Object = new A1{Bee = new B()};
A2 a2Object = Mapper.Map<A2>(a1Object);
I have a base class
public class A
{
public string s1;
public string s2;
}
I also have a derived class :
public class B : A
{
public string s3;
}
Suppose my program created an instance of class A.
A aClassInstance = new A();
some parameters were set:
aClassInstance.s1 = "string 1";
aClassInstance.s2 = "string 2";
At this point I would like to create an instance of class B. But I would like B to already have the values of my instance of class A.
This DID NOT Work:
public B bClassInstance = new B():
bClassInstance = (B)aClassInstance;
NEITHER DID THIS:
Made a clone method within Class A.
public B cloneA() {
A a = new A();
a = (A)this.MemberwiseClone()
return(B)a;
}
The VS code takes both of the above - but I get run-time errors
Please help
The base problem you have is, that you have to construct an instance of type B (which contains of cause the properties of type A). Your approach to clone an A instance won't work, because that gives you an instance of type A, which you can't convert to B.
I would write constructors for class A and B which takes a parameter of type A. The constructor of class B just passes the value to its base class A. The constructor of class A knows how to copy the fields to itself:
class A {
public A(A copyMe) {
s1 = copyMe.s1;
...
}
class B : A {
public B(A aInstance) : base(aInstance) {
}
}
Use it this way:
A a = new A();
a.s1 = "...";
B b = new B(a);
EDIT
When you don't want to have to change the constructor of A when adding new fields or props, you could use reflection to copy the properties. Either use a custom attribute to decorate what you want to copy, or copy just all props/fields of A:
public A (A copyMe) {
Type t = copyMe.GetType();
foreach (FieldInfo fieldInf in t.GetFields())
{
fieldInf.SetValue(this, fieldInf.GetValue(copyMe));
}
foreach (PropertyInfo propInf in t.GetProperties())
{
propInf.SetValue(this, propInf.GetValue(copyMe));
}
}
I havn't tried the code, but the point should become clear.
You could create a generic clone method in class A:
public T Clone<T>() where T : A, new() {
return new T() { a = this.a, b = this.b};
}
Or if you want to make the cloning extendable:
public T Clone<T>() where T : A, new() {
var result = new T();
this.CopyTo(result);
return result;
}
protected virtual void CopyTo(A other) {
other.a = this.a;
other.b = this.b;
}
You use it like this:
A a = new A();
// do stuff with a
// Create a B based on A:
B b = a.Clone<B>();
Please note: in your example, both the new A(), and the MemberwiseClone will create a new object of type A.
If you do not want to code the copy method yourself, you could look at a tool like AutoMapper.
After playing around and reading everything I could get my eyes on, both of the above solutions by GvS and Jan work.
However, the end result that I wanted to achieve is not to be forced to write out each member in the Copy methods.
Why:
a) If the class is edited and another object is added, the copy method will have to be updated. If someone else updates the class, they may forget to do this.
b) There may be a lot of members, and assigning them may be time consuming.
c) It just doesn't "feel" right. (Probably because I am very lazy).
Fortunately, I am not the only one with the same thoughts. Found a very very easy solution via the ValueInjector. (it has been discussed on these boards a lot).
After getting the dll (http://valueinjecter.codeplex.com/documentation)
The code becomes:
A a = new A();
a.s1 = "...";
B b = new B();
b.InjectFrom(a);
That's it :)
Obviously you would have to include:
using Omu.ValueInjecter;
And not forget to add it to the references.
You can also use a JSON serializer for example. You add a static method to your child-class which could then be called like this:
var porsche = Porsche.FromCar(basicCar);
Here, "Porsche" is the child class and "Car" is the base class. The function would then look something like this:
public class Porsche : Car
{
public static Porsche FromCar(Car basicCar)
{
// Create a JSON string that represents the base class and its current values.
var serializedCar = JsonConvert.SerializeObject(basicCar);
// Deserialize that base class string into the child class.
return JsonConvert.DeserializeObject<Porsche>(serializedCar);
}
// Other properties and functions of the class...
}
The trick here is, that properties that are available in the child but not the base, will be created with their default value, so null usually, depending on the type of the property. The deserialization also goes by the name of the property, so all properties are copied over.
I didn't test this code, but it should work, as I've done this once or twice before. Hope it helps someone.
I'm trying to go the opposite way of what you would normally do.
I have two POCO classes A and B where B inherrits from A
public class A
{
public int Foo { get; set; }
}
public class B : A
{
public int Bar { get; set; }
}
B is ment as an extention to A with additional information.
I start by having an instance of class A
A a = new A { Foo = 1 };
And then I wish to extend the information in class A with the additional information and get the final class B. I could map every property from class A to the property in class B, but it does not make much sence to me:
A a = new A { Foo = 1 };
B b = new B { Foo = a.Foo, Bar = 2 };
Or in constructor
A a = new A { Foo = 1 };
B b = new B(a) { Bar = 2 }; // Mapping of value Foo is done in constructor of object B
The result is in eather case a manual mapping of values from object A to B.
There must be a smarter way to do this... any suggestions?
If you are actually changing type (rather than casting) - then if you have only a few classes, then just write conversion code - perhaps a ctor for B that accepts a template A. If you have a lot of classes... there are tricks you can do with either dynamic code or serialization. PropertyCopy in MiscUtil will do this, for example (using a dynamic Expression to do the work very quickly):
A a = new A { Foo = 1 };
B b = PropertyCopy<B>.CopyFrom(a);
b.Bar = 2;
I would regard the "smart" way as being your last suggestion - write a copy constructor for B that knows how to instantiate itself from an A.