Converting from base object to inherrited object - c#

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.

Related

List<Parent> holding Child element without losing properties C#

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.

NullReferenceException with object initializer suggested by resharper

I have a strange issue with the object initializer syntax.
Here are my sample classes:
public class Foo
{
public Bah BahProp { get; set; }
}
public class Bah
{
public int Id { get; set; }
}
Consider following three ways to initialize an object:
The old, verbose but explicit way, working correctly:
var foo1 = new Foo();
foo1.BahProp = new Bah();
foo1.BahProp.Id = 1;
// correctly initialized
The second way i'm always using, using object initializer syntax:
var foo2 = new Foo
{
BahProp = new Bah { Id = 1 }
}; // correctly initialized
A third way resharper has suggested my collegue with a different resharper version(is it a bug?):
var foo3 = new Foo
{
BahProp = { Id = 1 }
}; // NullReferenceException
What is the last approach doing differently?
My resharper version is 2016.1.1, my colleague was on 10.02. My resharper suggested the second way. But what does the third way do and when is it useful?
Update: So it seems that it was a bad resharper sugestion to use the last way, that's why they have changed it meanwhile to use the second way.
You can avoid the NullReferenceException if you want to use the third way by initializing all properties/fields that are reference types inline or in the constructor.
I will definitely not use this strange property assignment syntax.
new Foo { BahProp = { Id = 1 } }
compiles to:
new Foo().BahProp.Id = 1;
or, little more verbose:
var foo3 = new Foo();
foo3.BahProp.Id = 1;
So BahProp is null. You're not constructing it.
(This is perhaps the most confusing syntax in all of C#)
Option 2 works because you're calling the constructor of Bah.
Option 3 would also work if you initialize BahProp inside the constructor of Foo. It will have been constructed by the time BahProp = { Id = 1 } is called.
The same is seen with collection initializers:
public class Foo {
public List<int> Numbers { get; set; }
}
var foo = new Foo { Numbers = { 1, 2, 3 } };
This does not initialize the List. It only calls Add on it.
You really must see new MyObject() { X = 1, Y = 2 } as two distinct parts:
new MyObject() constructs a new object and
{ X = 1, Y = 2 } sets the values of its properties (and that's all it does).
Object and collection initializers can be nested. The top-level initializer must follow a constructor, but a nested initializer does not.

Copy property's values between 2 inherited classes

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);

How to cast an instance of these similar classes?

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);

C# inheritance. Derived class from Base class

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.

Categories