C# XML Deserializer not constructing object properly - c#

My class looks like this:
public class MyClass
{
private void MyClass() { } //just to satisfy the XML serializer
public void MyClass(int a, int b)
{
A = a;
B = b;
C = a + b;
}
public int A { get; set; }
public int B { get; set; }
public int C { get; private set; } //private set is only to
//satisfy the XML Serializer
public void DoSomeMath()
{
Console.WriteLine("{0} + {1} = {2}\n", A, B, C)
}
}
This works fine when I instantiate my own myClass object with a & b parameters, but the deserializer will only call the paramaterless constructor. How do I initialize C without creating another method and calling that after I deserialize?

Deserializing will just populate the variables - any other logic required to instantiate the object needs to be run by the program, not the deserializer. Try something like this:
public class MyClass
{
private void MyClass() // NOT just to satisfy the XML serializer
{
GetStuffReady();
}
public void MyClass(int a, int b)
{
A = a;
B = b;
GetStuffReady();
}
public int A { get; set; }
public int B { get; set; }
public int C { get; private set; }
public void GetStuffReady()
{
C = A + B;
}
public void DoSomeMath()
{
Console.WriteLine("{0} + {1} = {2}\n", A, B, C)
}
}
Or better yet:
public class MyClass
{
private void MyClass() { } //just to satisfy the XML serializer
public void MyClass(int a, int b)
{
A = a;
B = b;
}
public int A { get; set; }
public int B { get; set; }
public int C
{
get
{
return A + B;
}
set { }
}
public void DoSomeMath()
{
Console.WriteLine("{0} + {1} = {2}\n", A, B, C)
}
}
EDIT: If the variables need to be set before the logic is executed, you can create a blank instance of the class and then set the variables using a helper method that takes XML as an input. See the following answer for an example: When is the class constructor called while deserialising using XmlSerializer.Deserialize?

You can simply modify the getter for C like:
public int C { get { return this.A + this.B; }}

If you are using the regular binary formatter, then:
[OnDeserialized]
public void DoSomeMath()
{
Console.WriteLine("{0} + {1} = {2}\n", A, B, C)
}
For the XmlSerializer, events are not supported.
You could implement IXmlSerializable, but it's non trivial.
For DataContractSerializer (which serializes to xml) you could try:
[OnDeserializing]
public void OnDeserializing(StreamingContext context)
{
... // logic here.
}
There is an answer here to XmlSerializer but it requires inheriting the default one.
How do you find out when you've been loaded via XML Serialization?

Related

How to use same classes in different windows forms?

I am working on something in which i have 3 forms first form have two buttons which will take me to other two forms.
I did that already but my question is now i want to use the classes i made on form1 in other two forms.The classes i am using have simple private string variables and getter setters.
class class_1
{
private string n;
private string f;
private string a;
public void setn(string n) { n = n; }
public void setf(string f) { f = f; }
public void seta(string a) {a = a; }
public string getn() { return n; }
public string getf() { return f; }
public string geta() { return a; }
}
As discussed, Simply right click on the WinForm project, select add new item and choose class. Change this to be the same as the content of the class in your form and then remove the one on the form namespace. Remember to make it public
public class class_1
{
private string n;
private string f;
private string a;
public void setn(string n) { n = n; }
public void setf(string f) { f = f; }
public void seta(string a) {a = a; }
public string getn() { return n; }
public string getf() { return f; }
public string geta() { return a; }
}
Just a tip. I assume you are just learning but its good practice to name your classes accordingly. Don't leave it as class_1
thanks
Just create object of class_1 in your form1 and form2
like
class_1 obj = new class_1();
And then you'll be able to access property like
string temp = obj.getn;
And you don't have to create different getter setter,
c# has properties for that your code could be
class class_1
{
public string n { get; set; }
public string f { get; set; }
public string a { get; set; }
}
And that's same thing

Access class variable from another newly created class

I have code like this:
class First
{
public int a { get; set; }
public int b { get; set; }
public int c = 2;
public _second;
public First()
{
_second = new Second(c);
this.a = _second.a;
this.b = _second.b;
}
}
class Second
{
public int a;
public int b;
public Second(int c)
{
if(c == 0)
{
a = 1;
b = 2;
}
else
{
a = -1;
b = -2;
}
}
}
How can I pass a and b from First class into second class and then directly from second class set their values withohut using static as declaration in First class.
I have tried this:
class First
{
public int a;
public int b;
public int c = 2;
public _second;
public First()
{
_second = new Second(a, b, c);
}
}
class Second
{
public Second(int a, int b, int c)
{
if(c == 0)
{
a = 1;
b = 2;
}
else
{
a = -1;
b = -2;
}
}
}
but it is not doing the job.
You can simply add a constructor in the Second class that receives the instance of First and updates the public variables of the instance passed
public class Second
{
public Second(int a, int b, int c)
{
// old constructor if still needed
...
}
public Second(First f)
{
int sign = f.c == 0 ? 1 : -1;
f.a = 1 * sign;
f.b = 2 * sign;
}
}
By the way, I suggest to use properties instead of public fieds.
public class First
{
public int a {get;set;}
public int b {get;set;}
public int c {get;set;} = 2;
public Second _second {get;set;}
public First()
{
_second = new Second(this);
}
}
UPDATE
Looking at your image it is clear what is the source of your problem. You are receiving a Form class instance in your Forma constructor. You need to receive a Main instance like
public Forma(Main form, int modulID)
{
.....
}
The base class Form has no knowledge of methods defined in custom form classes. In alternative you can still receive a Form instance but you need to add something like this
public Forma(Form form, int modulID)
{
Main m = form as Main;
if(m != null)
m.helpWindow = new Help(modulID);
}
.....
}
You can pass the fields as ref meaning that you pass a reference to the field passed as parameter not the value. This means changes to the fields inside the Second constructor will be reflected in the First class
class First
{
public int a;
public int b;
public int c = 2;
public Second _second;
public First()
{
_second = new Second(ref a, ref b, c);
}
}
class Second
{
public Second(ref int a, ref int b, int c)
{
if (c == 0)
{
a = 1;
b = 2;
}
else
{
a = -1;
b = -2;
}
}
}
You can pass by ref to any method not just a constructor. You should read more about this topic, here for example
I accomplished it with Interface.
public interface IClass
{
int a { get; set; }
int b { get; set; }
}
class First : IClass
{
public int a { get; set; }
public int b { get; set; }
public int c = 2;
public _second;
public First()
{
_second = new Second(this, c);
}
}
class Second
{
public Second(IClass ic, int c)
{
if(c == 0)
{
ic.a = 1;
ic.b = 2;
}
else
{
ic.a = -1;
ic.b = -2;
}
}
}

How to access public Property MyProperty of class A in class C

I have following code:
public class A
{
public int MyProperty {get; set;}
}
public class B
{
A myInstance = new A();
myInstance.MyProperty = 10;
}
public class C
{
public void InvokeA()
{
//How to access MyPropery here?
BInstance = new B();
Console.WriteLine(B.myInstance.MyProperty.ToString());
}
}
I'm looking for a way to access MyProperty as written above. Inheritance is not an option since my class C is already inherited from some base class. A way without declaring any of the given classes as static would be nice!
Thanks,
Orz
Consider following classes:
public class A
{
public int MyProperty { get; set; }
}
public class B
{
public A GetAInstance()
{
A myInstance = new A();
myInstance.MyProperty = 10;
return myInstance;
}
}
public class C
{
private B BInstance;
public void InvokeA()
{
BInstance = new B();
Console.WriteLine(BInstance.GetAInstance());
}
}
and then you will create your C instance in Main:
static void Main(string[] args)
{
C cInstance = new C();
cInstance.InvokeA();
}
In order to accomplish your goal, you need to expose B.MyInstance as a property of the B class, just like you exposed A.MyProperty as a property of the A class.
Edit: Per the comments of others regarding use of the static keyword, here's what you might want your code to look like:
public class A
{
public int MyProperty { get; set; }
}
public static class B
{
static B()
{
MyInstance = new A();
MyInstance.MyProperty = 10;
}
public static A MyInstance { get; set; }
}
public class C
{
// not sure what your intention is here
public C()
{
System.Console.WriteLine(B.MyInstance.MyProperty.ToString()); // "10\n"
}
}
Yes. You can inherits classes from A to B something like this:
public class A
{
public int MyProperty {get; set;}
}
public class B : A
{
public B()
: A()
{
MyProperty = 1;
}
}
Now you can do:
(new B()).MyProperty
Or use Singleton approach to resolve:
public class B
{
private static _a;
public class A
{
public int MyProperty {get; set;}
}
public static A AA {
if (_a == null) {
_a = new A();
}
return _a;
}
}
This implmentation will return
B.A.MyProperty.ToString();

Copy some properties into new constructor

I have a big class with a lot of properties (BigClass). I need to make a new class (SmallClass) with only some of those properties. This SmallClass must use all the overlapping properties from BigClass. What is the easiest way to do this without having to manually assign all the properties in the constructor of SmallClass like I do below:
class BigClass
{
public int A { get; }
public int B { get; }
public int C { get; }
public int D { get; }
public int E { get; }
public BigClass(int a, int b, int c, int d, int e)
{
A = a;
B = b;
C = c;
D = d;
E = e;
}
}
class SmallClass
{
public int A { get; }
public int B { get; }
public int C { get; }
public SmallClass(BigClass bigClass)
{
// I don't want to do all this manually:
A = bigClass.A;
B = bigClass.B;
C = bigClass.C;
}
}
Create a helper class:
public class Helper
{
public static void CopyItem<T>(BigClass source, T target)
{
// Need a way to rename the backing-field name to the property Name ("<A>k__BackingField" => "A")
Func<string, string> renameBackingField = key => new string(key.Skip(1).Take(key.IndexOf('>') - 1).ToArray());
// Get public source properties (change BindingFlags if you need to copy private memebers as well)
var sourceProperties = source.GetType().GetProperties().ToDictionary(item => item.Name);
// Get "missing" property setter's backing field
var targetFields = typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetField).ToDictionary(item => renameBackingField(item.Name));
// Copy properties where target name matches the source property name
foreach(var sourceProperty in sourceProperties)
{
if (targetFields.ContainsKey(sourceProperty.Key) == false)
continue; // No match. skip
var sourceValue = sourceProperty.Value.GetValue(source);
targetFields[sourceProperty.Key].SetValue(target, sourceValue);
}
}
}
Then in your SmallClass constructor:
public SmallClass(BigClass bigClass)
{
Helper.CopyItem(bigClass, this);
}
This should work even if you only have property getters.
You can make CopyItem to work with all types by changing its declaration;
public static void CopyItem<U, T>(U source, T target)

C# Avoid Multiple SWITCH Statements .net

Please excuse bursts of stupidity as I learn the intricacies of C# / .NET
Say I have three classes with multiple static properties (more than three but for arguments sake..)
CLASS FOO
public static A
{
get / set A;
}
public static B
{
get / set B;
}
public static C
{
get / set C;
}
CLASS BAR
{
get / set A;
}
public static B
{
get / set B;
}
public static C
{
get / set C;
}
CLASS YOO
{
get / set A;
}
public static B
{
get / set B;
}
public static C
{
get / set C;
}
And from another class I need to update one or several static properties in each class multiple times... How do I keep from writing multiple SWITCH statments like this...
public void updateVarx(string class, string varx)
{
string y = 'class'
SWITCH (y)
{
case FOO:
FOO.A = Varx;
break;
case BAR:
BAR.A = Varx;
break;
case YOO:
YOO.A = Varx;
break;
}
}
And then another one when I want to update B varY:
public void updateVary(string class, string vary)
{
string y = 'class'
SWITCH (y)
{
case FOO:
FOO.B = Vary;
break;
case BAR:
BAR.B = Vary;
break;
case YOO:
YOO.B = Vary;
break;
}
}
Since you are learning .net/c#, I guess i should warn you, using static properties is probably not the way to go in object oriented programming.
Static is global state and is dangerous. If you end up using multi-threaded code, you have to be super careful. If you need only one instance, just instantiate one, but don't go creating static properties on a class, unless you have a pretty good reason to add them (And I can't think of any right now).
In fact, in well designed, object oriented code you sould probably not have many if, switch, getters or setters either.
Let's say you need different behaviors on your classes, you can do it this way.
Interface ISecurity {
void UpdateVarX(int value);
void UpdateVarY(int value);
int GetValueX();
int GetValueX();
}
class Foo:ISecurity {
// Implement methods of the interface
}
class Bar:ISecurity {
// Implement methods of the interface
}
class Yoo:ISecurity {
// Implement methods of the interface
}
// This class is the class that uses your other classes
class Consumer
{
private ISecurity sec;
public Consumer(ISecurity sec) {
sec.UpdateVarX(25);
}
}
Or if as in your example, all your static classes have the same properties:
public class Settings {
public int A {get; set;}
public int B {get; set;}
public int C {get; set;}
}
public class NeedsToUseOtherClass {
public NeedsToUseOtherClass() {
Settings foo = new Settings();
Settings bar = new Settings();
Settings yoo = new Settings();
foo.setA(25);
}
}
Maybe I am not understanding the problem but if all your classes have the same exact properties then you can just pass the object (FOO, BAR, or YOO) into UpdateVarx or UpdateVary methods and just implement an interface? Something along these lines:
public class FOO : IHasStatus
{
public A
{
get / set A;
}
public B
{
get / set B;
}
public C
{
get / set C;
}
}
public void updateVarx(IHasStatus someObject, string varx)
{
someObject.A = varx;
}
public void updateVary(IHasStatus someObject, string vary)
{
someObject.B = vary;
}
If you don't need the concrete classes, you can abstract out the logic like so:
public class Status {
public string A {
get; set;
}
public string B {
get; set;
}
public string C {
get; set;
}
}
public static class StatusManager {
private static Dictionary<string, Status> statusMap = new Dictionary<string,Status>();
public static Status GetStatus(string name) {
Status status;
if (!statusMap.TryGetValue(name, out status))
statusMap[name] = status = new Status();
return status;
}
public static void SetStatus(string name, Status status) {
statusMap[name] = status;
}
public static void UpdateVarx(string name, string varx) {
GetStatus(name).A = varx;
}
// ...
}
If you are a fan of the javascript way of solving multiple switch cases like this
you can always wrap up the switch handlers as Actions and toss them in a Dictionary.
For example : (Source obtained from here)
public class SwitchCase : Dictionary<string,Action>
{
public void Eval(string key)
{
if (this.ContainsKey(key))
this[key]();
else
this["default"]();
}
}
//Now, somewhere else
var mySwitch = new SwitchCase
{
{ "case1", ()=>Console.WriteLine("Case1 is executed") },
{ "case2", ()=>Console.WriteLine("Case2 is executed") },
{ "case3", ()=>Console.WriteLine("Case3 is executed") },
{ "case4", ()=>Console.WriteLine("Case4 is executed") },
{ "default",()=>Console.WriteLine("Default is executed") },
};
mySwitch.Eval(c);
Below code uses all kinds of hacks, not really recommended in production code unless you have a very good reason.
using System;
using System.Linq;
namespace ConsoleApplication1
{
static class Program
{
private static void SetStaticProperty(string className, string propName, string varx)
{
//This sucks, I couldnt find the namespace with easily through reflection :(
string NAMESPACE = "ConsoleApplication1";
Type t = Type.GetType(NAMESPACE + "." + className);
t.GetProperties().Where(p => p.Name == propName).First().SetValue(null, varx, null);
}
public static void updateVarx(string className, string varx)
{
SetStaticProperty(className, "A", varx);
}
public static void updateVary(string className, string vary)
{
SetStaticProperty(className, "B", vary);
}
static void Main(string[] args)
{
updateVarx("Foo", "FooAstring");
updateVarx("Bar", "BarAstring");
updateVarx("Yod", "YodAstring");
updateVary("Foo", "FooBstring");
updateVary("Bar", "BarBstring");
updateVary("Yod", "YodBstring");
Console.WriteLine(Foo.A);
Console.WriteLine(Foo.B);
Console.WriteLine(Bar.A);
Console.WriteLine(Bar.B);
Console.WriteLine(Yod.A);
Console.WriteLine(Yod.B);
Console.ReadLine();
}
}
class Foo
{
public static string A { get; set; }
public static string B { get; set; }
public static string C { get; set; }
}
class Bar
{
public static string A { get; set; }
public static string B { get; set; }
public static string C { get; set; }
}
class Yod
{
public static string A { get; set; }
public static string B { get; set; }
public static string C { get; set; }
}
}
You can use dictionary as configuration and remove the switch statement
Create a dictionary and add append data as below for mapping
//Have dictionary setted up
Dictionary<string, dynamic> m_Dictionary = new Dictionary<string, dynamic>();
m_xmlDictionary.Add("classA",FOO);
m_xmlDictionary.Add("classB",BAR);
m_xmlDictionary.Add("classC",BAR);
//Have dictionary setted up
//change the function as below
public void updatevarx(string class, string varx)
{
m_Dictionary[class].A=varx // Replaced switch statement
}
//while calling use
updatevarx("classC","abc!");// This will assign BAR.A with abc!

Categories

Resources