I might be currently confused, but I have the following problem.
I'm using C# but the point is more general, but I'm new to C# coming from Java.
I have a common abstract super class and multiple children.
Some children have generic properties which I can't access when I'm instantiating the a variable when declaring the common super type:
abstract class A
{
public string Prop0;
}
// Here every ok when instantiated
class B: A
{
public string Prop1;
}
// This makes trouble
class C<T> : A
{
public T Prop2;
}
Now I have a method which returns some subtype of A:
public A DoIt()
{
A a;
a = new C<string>();
a.Prop2; // <-- Can't access
}
(In my concrete case, the type can't be static because the child classes are serialized and have different shapes (C is a template with a property allowing anything). Still the question is general)
Why is this an issue and which solution is "correct" (except of using "object")
If a is always going to be set to a new instance of a C, then simply declare it as such:
public A DoIt()
{
C<string> c;
c = new C<string>();
var prop2 = c.Prop2;
return c;
}
But if you won't know if it's a C or not until it gets deserialized -- which it sounds from your explanation is the case here -- then here's a way to get that property if in fact it is a C (or get null if it's not a C):
public A DoIt()
{
A a;
a = new C<string>();
var prop2 = a is C<string> ? (a as C<string>).Prop2 : null;
return a;
}
Basically what this second approach does is check to see if a is an instance of C, and if so, it casts a to C and then reads its Prop2 property.
FOLLOW-UP EXAMPLE:
Here's code from an actual working console app that does something similar to what you've described. It's not a realistic scenario, and it may not be even close what you had in mind, but I'll post it anyway in case it gives you any ideas.
Note that this requires a reference to Json.NET (for the using Newtonsoft.Json; statement below).
using System;
using Newtonsoft.Json;
...
static void Main(string[] args)
{
var c = new C<string>() { Prop0 = "zero", Prop2 = "two" };
var json = JsonConvert.SerializeObject(c);
var prop2 = GetProp2(json);
Console.WriteLine("prop2 from C: " + (prop2 ?? "null"));
var b = new B() { Prop0 = "zero", Prop1 = "one" };
json = JsonConvert.SerializeObject(b);
prop2 = GetProp2(json);
Console.WriteLine("prop2 from B: " + (prop2 ?? "null"));
Console.Write("Press any key to exit...");
Console.ReadKey();
}
static object GetProp2(string json)
{
A a = JsonConvert.DeserializeObject<C<string>>(json);
var prop2 = a is C<string> ? (a as C<string>).Prop2 : null;
return prop2;
}
Results in the following output:
prop2 from C: two
prop2 from B: null
Press any key to exit...
Potential answer to question in comment: "How do you declare that some subtype of Shape shall be returned/instantiated".
If you want to specifically return C<T> results you can specify it as return type:
public C<TResult> DoIt<TResult>()
{
C<TResult> a;
a = new C<TResult>();
a.Prop2; // <-- Can access
return 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 am wondering about the best approach to the below
I have a .NET Web application and I am changing the ORM provider I am using. To do this I have created a new solution and removed the previous ORM and implemented my new one. As there are lots of existing screens that work with the previous ORM I want to make sure that the same object is returned by both ORMS. As these are in two separate VS slns is there a simple way I can compare the complex objects that all the same properties have been loaded on to the object graph. I could set a breakpoint and compare them manually but I don't really want to do this?
If this is for testing purposes, you can use FluentAssertions to check this.
The following code declares two unrelated types, ClassA and ClassB which contain two nested classes both called A and B but of different types.
Therefore the containing classes and the nested classes are of unrelated types, but the names of the members are the same, and for the nested classes the types of the properties are the same.
You can use FluentAssertions to test if the two instances classA and classB are equivalent - even though they are of different types - as follows:
using System;
using FluentAssertions;
namespace Demo
{
class ClassA
{
public NestedClassA A;
public NestedClassB B;
}
class NestedClassA
{
public string S;
public int I;
}
class NestedClassB
{
public char C;
public double D;
}
class ClassB
{
public NestedClassC A;
public NestedClassD B;
}
class NestedClassC
{
public string S;
public int I;
}
class NestedClassD
{
public char C;
public double D;
}
internal class Program
{
private static void Main()
{
var nestedA = new NestedClassA {I = 1, S = "1"};
var nestedB = new NestedClassB {C = '1', D = 1};
var nestedC = new NestedClassC { I = 1, S = "1" };
var nestedD = new NestedClassD { C = '1', D = 1 };
var classA = new ClassA {A = nestedA, B = nestedB};
var classB = new ClassB {A = nestedC, B = nestedD};
classA.ShouldBeEquivalentTo(classB); // Passes
classB.ShouldBeEquivalentTo(classA); // Passes
classB.B.D = 2; // Now the two objects do not contain equivalent data.
classA.ShouldBeEquivalentTo(classB); // Fails.
}
}
}
So I am guessing it is not as simple as to implement the IEquatable interface and directly compare your instances using this. You have to be aware that implementing proper comparing methods will be the fastest way.
But there are slower, more flexible ways. I think what you want to do is:
Compare two objects of unknown types
Check if they contain class variables with the same name
Check if the class variables have matching types
Check if the values in the variables are the same
There is only one way to do that. And it is to throw System.Reflection at the problem. Mind that this solution will be considerably slower then all solutions that work with known types.
So you need your ComplexEquals function.
public static bool ComplexEquals(object obj1, object obj2)
{
if (obj1 == null && obj2 == null) return true;
if (obj1 == null || obj2 == null) return false;
var obj1Class = obj1.GetType();
var obj2Class = obj2.GetType();
/* Get the instance fields (all of them) of both classes. */
var obj1Fields = obj1Class.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
var obj2Fields = obj2Class.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
var checkedFields = new HashSet<String>();
foreach (var obj1Field in obj1Fields)
{
var fieldName = obj1Field.Name;
checkedFields.Add(fieldName);
var obj2Field = obj2Fields.Where(f => f.Name == fieldName).SingleOrDefault();
if (obj2Field == null) return false;
if (obj1Field.FieldType == obj2Field.FieldType && !(obj1Field.GetValue(obj1).Equals(obj2Field.GetValue(obj2)))) return false;
}
if (obj2Fields.Any(f => !checkedFields.Contains(f.Name))) return false;
return true;
}
This is a simple version that relies on the Equals function starting at the first level inside the unknown function. This may be sufficient or not. But I think that is a starting point that can be extended if required.
I have a class, that should support version tolerant serialization
[Serializable]
class A {
[OptionalField]
int a;
[OptionalField]
MyClass b;
[OptionalField]
MyClass c;
}
How can I correct missing fields after deserialization? I guess, I have to use method marked with [OnDeserializing]. But how can I get which of fields was ignored?
Can I configure auto-deserialization to initialize field by default constructor in case of them missing?
Additionally, you can use OnSerializingAttribute and OnSerializedAttribute to set the fields. As the example shows, fields that have been already set will keep their value. Note, however, that this is only the case if the field is set during the OnSerializing event. Fields set during the OnSerialized event will override the serialized value.
EDIT: In this case you can check in your method (decorated with OnSerialized) if the field equals to null and instantiate when necessary. If there is the possibility that this field is never be used and its creation can be deferred, think about hiding the field in question behind a property and instantiate it lazily.
Models.cs:
using System;
using System.Runtime.Serialization;
namespace SerializationExample
{
[Serializable]
public class Model
{
public Model(){
A = new SomeClass();
}
[OptionalField]
public int value;
[OptionalField]
public SomeClass A;
[OptionalField]
public AnotherClass B;
[OnDeserializing]
void OnDeserializing(StreamingContext context)
{
B = new AnotherClass("Set during deserializing");
}
[OnDeserialized]
void OnDeserialized(StreamingContext context)
{
// Do sth. here after the object has been deserialized
}
public override string ToString()
{
return String.Format("A: {0}\nB: {1}", A, B);
}
}
[Serializable]
public class SomeClass
{
public string Value { get; set; }
public SomeClass()
{
Value = "Default";
}
public override string ToString()
{
return Value;
}
}
[Serializable]
public class AnotherClass
{
public string Value { get; private set; }
public AnotherClass(string v)
{
Value = v;
}
public override string ToString()
{
return Value;
}
}
}
Program.cs:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace SerializationExample
{
class Program
{
static void Main(string[] args)
{
string[] FileNames = new string[] {
#"model1.bin",
#"model2.bin"
};
Stream[] files = new Stream[] {
File.Create(FileNames[0]),
File.Create(FileNames[1])
};
BinaryFormatter bf = new BinaryFormatter();
Model m1 = new Model();
m1.B = new AnotherClass("Set in app");
m1.A.Value = "Set in app";
Model m2 = new Model();
Console.WriteLine("M1:\n{0}\n", m1);
Console.WriteLine("M2:\n{0}\n\n", m2);
bf.Serialize(files[0], m1);
bf.Serialize(files[1], m2);
foreach (var f in files)
f.Seek(0, SeekOrigin.Begin);
m1 = null;
m2 = null;
m1 = (Model)bf.Deserialize(files[0]);
m2 = (Model)bf.Deserialize(files[1]);
Console.WriteLine("M1:\n{0}\n", m1);
Console.WriteLine("M2:\n{0}\n\n", m2);
foreach (var f in files)
f.Close();
}
}
}
Output:
M1:
A: Set in app
B: Set in app
M2:
A: Default
B:
M1:
A: Set in app
B: Set in app
M2:
A: Default
B: Set during deserializing
If you just want to initialize those values to defaults, all you need is a default parameterless constructor that initializes them. This will get called during deserialization, and any missing fields will keep whatever values you initialized them to in the constructor.
If you want more control, you can implement the ISerializable interface and the proper constructor on your class (you should usually do both, though often one or the other is unneeded.)
If C# finds a constructor with the signature:
protected A ( SerializationInfo info, StreamingContext context )
{
}
it will call that constructor, and pass a weakly-typed dictionary with all of the serialization information it has. (You can use ISerializable::GetObjectData to write custom fields into the object and retrieve them in the constructor). You can use the info.GetXXX methods to extract those values.
One thing to note: if you implement this constructor, you have to do all of the work, including the fields that would normally get deserialized automatically. For any missing fields, just set them appropriately. Similarly, if you implement GetObjectData, you have to serialize everything in that method. It's pretty simple, but if you change your class you need to edit your custom method/constructor appropriately.
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.
This question already has answers here:
How do you do a deep copy of an object in .NET? [duplicate]
(10 answers)
Closed 3 years ago.
Please have a look at the code below (excerpt from a C# book):
public class MyClass
{
public int val;
}
public struct myStruct
{
public int val;
}
public class Program
{
private static void Main(string[] args)
{
MyClass objectA = new MyClass();
MyClass objectB = objectA;
objectA.val = 10;
objectB.val = 20;
myStruct structA = new myStruct();
myStruct structB = structA;
structA.val = 30;
structB.val = 40;
Console.WriteLine("objectA.val = {0}", objectA.val);
Console.WriteLine("objectB.val = {0}", objectB.val);
Console.WriteLine("structA.val = {0}", structA.val);
Console.WriteLine("structB.val = {0}", structB.val);
Console.ReadKey();
}
}
I understands it produces the output below:
objectA.val = 20
objectB.val = 20
structA.val = 30
structB.val = 40
The last two lines of the output I have no problem with, but the first two tell me that objectA and objectB are pointing to the same memory block (since in C#, objects are reference types).
The question is how do make objectB, a copy of objectA so that it points to a different area in memory. I understand that trying to assign their members may not work since those members may be references, too. So how do I go about making objectB a completely different entity from objectA?
You could do:
class myClass : ICloneable
{
public String test;
public object Clone()
{
return this.MemberwiseClone();
}
}
then you can do
myClass a = new myClass();
myClass b = (myClass)a.Clone();
N.B. MemberwiseClone() Creates a shallow copy of the current System.Object.
There is no built-in way. You can have MyClass implement the IClonable interface (but it is sort of deprecated) or just write your own Copy/Clone method. In either case you will have to write some code.
For big objects you could consider Serialization + Deserialization (through a MemoryStream), just to reuse existing code.
Whatever the method, think carefully about what "a copy" means exactly. How deep should it go, are there Id fields to be excepted etc.
The easiest way to do this is writing a copy constructor in the MyClass class.
Something like this:
namespace Example
{
class MyClass
{
public int val;
public MyClass()
{
}
public MyClass(MyClass other)
{
val = other.val;
}
}
}
The second constructor simply accepts a parameter of his own type (the one you want to copy) and creates a new object assigned with the same value
class Program
{
static void Main(string[] args)
{
MyClass objectA = new MyClass();
MyClass objectB = new MyClass(objectA);
objectA.val = 10;
objectB.val = 20;
Console.WriteLine("objectA.val = {0}", objectA.val);
Console.WriteLine("objectB.val = {0}", objectB.val);
Console.ReadKey();
}
}
output:
objectA.val = 10
objectB.val = 20
There's already a question about this, you could perhaps read it
Deep cloning objects
There's no Clone() method as it exists in Java for example, but you could include a copy constructor in your clases, that's another good approach.
class A
{
private int attr
public int Attr
{
get { return attr; }
set { attr = value }
}
public A()
{
}
public A(A p)
{
this.attr = p.Attr;
}
}
This would be an example, copying the member 'Attr' when building the new object.