C# Update Object Properties without breaking instance - c#

I want to update an instance with properties of a newly created object at once but not breaking the instance binding to other variables. For eg.
public class MyClass{
public double X;
public double Y;
}
MyClass a = new MyClass(2,1);
MyClass b = a;
MyClass c = new MyClass(1,1);
a = c; //'b' should also be equal to 'a'.
//I dont want to do something like this:
a.Y = c.Y;
a.X = c.X;
In my code, 'b' is actually not accessible anymore because it is binded to some UI, 'a' is my only way through updating 'b'. So after 'a = c' is called, b should have the location of [1,1].

Experimental : please feel free to "blow this out of the water" :) Tested in VS 2010 beta 2 against FrameWork 4.0 and 3.5 (full, not "client" versions).
private class indirectReference
{
// using internal so Loc is not visible outside the class
internal struct Loc
{
public double X;
public double Y;
}
// publicly exposed access to the internal struct
public Loc pairODoubles;
// ctor
public indirectReference(double x, double y)
{
pairODoubles.X = x;
pairODoubles.Y = y;
}
}
// test ...
indirectReference r1 = new indirectReference(33, 33);
indirectReference r2 = r1;
indirectReference r3 = new indirectReference(66, 66);
// in this case the doubles in r2 are updated
r1.pairODoubles = r3.pairODoubles;

You could do something like this:
class Wrapper
{
public Wrapper(Location l)
{
this.L = l;
}
public Location L;
}
Wrapper a = new Wrapper(new Location(2,1));
Wrapper b = a;
Location c = new Location(1,1);
a.L = c;
I'm not sure whether it's really appropriate without more context. Just add a level of indirection.

Don't you think making the MyClass immutable would be a suitable approach?
Or: you should perform some reference counting, through a wrapper.

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.

Add lists to another list class

My code has 3 classes (a, b, c), that (b,c) classes inherit a. and I have a list (list mylist). My prblem is about adding to element from class b or class c
public class A
{
public int x;
public int y;
public A(int x, int y)
{
this.x = x;
this.y = y;
}
}
public class B : A
{
public int z;
public B(int x, int y, int z) : base(x, y)
{
}
}
class Program
{
static void Main(string[] args)
{
var myA = new List<A>();
myA.Add(new A(1, 2));
myA.Add(new B(3, 4, 5));
Console.WriteLine(myA[1]);
Console.WriteLine("0.x=" + myA[0].x + "--0.y=" + myA[0].y);
Console.WriteLine("1.x=" + myA[1].x + "--1.y=" + myA[1].y + "--1.z=");// I can't see myA.z
}
}
I've removed my former answer since you updated the question a lot.
The reason you don't see the property is because (as mentioned in a comment), the list only contains a "contract" to contain instances of the class A. Even if it also containes derrived classes (such as class B), it still isn't valid to access properties of B, because we can only ever be "certain" that the elements inside the list contain at least all the behavior and properties of A.
This is by design to ensure that we can't accidentally try accessing a property which doesn't exist for an instance of A during runtime.

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# copy 2D array (grid) with inherited unkown type

Say we have a base class A which is abstract:
abstract class A {
//code for class A
}
Also we have a subclass B which inherits from A and contains a copy constructor:
class B : A {
//some other membervariables and methods
public B (B copy) {
//makes a copy
}
}
Now suppose we make a class GridObject which we want to inherit from A, and the grid elements it contains are also a type of A, but might be of type B or any other class that inherits from A:
class GridObject : A {
A[,] grid;
public GridObject (int columns, int rows) {
grid = new A[columns, rows];
}
public GridObject (GridObject copy) {
//makes a copy
}
public Add (A obj, int x, int y) {
grid[x,y] = obj;
}
Now, my problem is how to make a copy constructor that makes an exact copy of the GridObject. Suppose we do this:
B b = new B();
GridObject gridObject = new GridObject(5, 5);
for (int x = 0; x < 5; x++)
for(int y = 0; y < 5; y++)
gridObject.Add(new B (b), x, y);
Now, what is the best way to implement a (deep) copy constructor for the class GridObject? Note that the elements of our gridObject are of type B now. But this also might have been any other arbitrary class that inherits from A.
Look at implementing System.IConeable[1] in A, and then overriding this for each of the inheriting classes. Each class can then be responsible for knowing how to clone itself.
[1] http://msdn.microsoft.com/en-us/library/system.icloneable.aspx
For a generic deep copy helper method, see this SO question.
I'm not sure your classes should be responsible for making the copies though. Is there ever a chance a single object can be in two locations? Obviously I don't see the full implementation so I may be missing the use case, but I'd do something like this:
B b = new B();
GridObject gridObject = new GridObject(5, 5);
for (int x = 0; x < 5; x++)
for(int y = 0; y < 5; y++)
gridObject.Add(b.DeepClone(), x, y);
Note that I'm passing the copy into the constructor rather than relying on the constructor to make a copy for me.

Converting from base object to inherrited object

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.

Categories