Control Instances of a class - c#

I have implemented a class as below:
public class Person
{
public int d, e, f;
public Person()
{
}
public Person(int a)
{
}
public Person(int a, int b)
{
new Person(40, 6, 8);
}
public Person(int a, int b, int c)
{
d = a; e = b; f = c;
}
}
public class Program
{
static void Main(string[] args)
{
Person P = new Person(100, 200);
Console.WriteLine("{0},{1},{2}", P.d, P.e, P.f);// it prints 0,0,0
}
}
Now if I create the instance of Person class with two arguments I am unable to set the values of d,e,f which is because in the third constructor a new object of Person is declared all together.
So the previous object does not have any idea about this new one.
Is there any way I can get hold of this new object and assign values to d,e,f from there?

I think you're actually trying to chain constructors together, so that one constructor passes arguments to another:
public Person(int a, int b) : this(40, 6, 8)
{
}
It's odd that you're ignoring a and b though... normally you'd just default one value, e.g.
public Person(int a, int b) : this(a, b, 8)
{
}
See my article on constructor chaining for more details.

public Person()
: this(0,0,0)
{
}
public Person(int a)
: this(a,0,0)
{
}
public Person(int a, int b)
: this(a,b,0)
{
}
public Person(int a, int b, int c)
{
d = a; e = b; f = c;
}

The default value of an int is 0. Use int? and test if it has a value.
e.g.
var d = P.d.HasValue ? P.d : "";
var e = P.e.HasValue ? P.e : "";
var f = P.f.HasValue ? P.f : "";
Console.WriteLine("{0},{1},{2}", d, e, f);

You can write this
public Person(int a, int b)
: this(40, 6, 8)
{
}
to call the other constructor.

Related

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

C# editing and adding function to nested class of abstract class

I have the abstract class shown below. It's nested class B is where I would like to define new functions.
public abstract class A {
public string varA = "Default";
public class B {
public B() {
}
public abstract somethingCool(int[] val);
}
}
public class C:A {
//set B functions
}
Is there a particular reason you NEED B to be a nested class? Why not just let your A class have a property of type B? Also, the somethingCool method needs a return type.
public abstract class A
{
public string varA = "Default";
public B InstanceOfB { get; set; }
}
public abstract class B
{
public abstract void SomethingCool(int[] val);
}
public class C : A
{
public override void SomethingCool(int[] val)
{
//do something cool
}
}
I'm not sure what you are trying to do, but if you want to implement B's functions from C, then mark B as abstract and subclass it in C. You can then override the abstract somethingCool method. Something like this:
public abstract class A
{
public string varA = "Default";
public abstract class B
{
public B() {}
public abstract void somethingCool(int[] val);
}
public void Foo(B bar, int[] val)
{
bar.somethingCool(val);
}
}
public class C : A
{
// set B functions
public class D : A.B
{
public override void somethingCool(int[] val)
{
for (int i = 0; i < val.Length; ++i)
{
System.Console.Write(string.Format("{0} ", val[i]));
}
}
}
}
Note that you can also subclass B from outside C:
public class E : A.B
{
public override void somethingCool(int[] val)
{
for (int i = val.Length - 1; i >= 0; --i)
{
System.Console.Write(string.Format("{0} ", val[i]));
}
}
}
Results:
public class Test
{
public void Test()
{
int[] val = new int[] { 1, 2, 3 };
var C = new C();
var D = new C.D();
C.Foo(D, val); // should print 1 2 3
var E = new E();
C.Foo(E, val); // should print 3 2 1
}
}

C# XML Deserializer not constructing object properly

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?

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)

How to work with object initialization and classes in C#

I have a class
class TestFixture
{
public string a { get; set; }
public int b { get; set; }
public int c { get; set; }
public string d { get; set; }
public string e { get ; set ; }
public int f { get; set; }
public int g { get; set; }
public bool h { get; set; }
public string i { get; set; }
public bool j { get; set; }
public bool k { get; set; }
public TestFixture()
{
e= dosomething(a, b);
f= false;
g = DateTime.Now.ToString("yyMMddhhmmss");
h= TestName.Equals("1") && b.Equals("2") ? 1000 : 1;
i= 10000000;
j= a.Equals("FOT");
k = false;
}
}
I want to define new TestFixture as SO
new TestFixture { a = "", b = 1, c=2, d="" };
while the rest of properties should be auto defined as it written in constructor.
Is it possible ?
Yes, this is possible. Using an object initializer does not skip calling the constructor.
TestFixture fixture = new TestFixture() // or just new TestFixture { ... }
{
a = "",
b = 1,
c = 2,
d = ""
};
This will call the constructor you've defined and then set a, b, c, and d in your object initializer.
Pop a breakpoint in your constructor and run your debugger. This is should show you how and when things in your code are called.
Debugging in Visual Studio
Refactored:
public class TestFixture
{
public string a { get; set; }
public int b { get; set; }
public int c { get; set; }
public string d { get; set; }
// dosomething should check for null strings
public string e { get { return dosomething(a, b); } }
public int f { get; set; }
public int g { get; set; }
public bool h
{
get { return TestName.Equals("1") && b.Equals("2") ? 1000 : 1; }
}
public string i { get; set; }
public bool j { get { return a != null && a.Equals("FOT"); } }
public bool k { get; set; }
public TestFixture(string a, int b, int c, string d)
: this()
{
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
public TestFixture()
{
f = false;
g = DateTime.Now.ToString("yyMMddhhmmss");
i = 10000000;
k = false;
}
}
#hunter's answer is correct, you can use object initializer syntax, and those properties will be set after your constructor runs. However, I'd like to point out some flaws you may have with your code
public TestFixture()
{
e= dosomething(a, b);
f= false;
g = DateTime.Now.ToString("yyMMddhhmmss");
h= TestName.Equals("1") && b.Equals("2") ? 1000 : 1;
i= 10000000;
j= a.Equals("FOT");
k = false;
}
This code does not set a or b, but you have things that depend on their values (e, g, j). Object initializer syntax is not going to be useful here, you have to have proper defaults for these values if other values in the constructor will depend upon them.
As an example, when you write var obj = new Bar() { A = "foo" };, that will expand to
var obj = new Bar(); // constructor runs
obj.A = "Foo"; // a is set
Clearly, the code in the constructor that looks at A will not see the value "Foo". If you need it to see this value, object initialization strategy is not going to help. You need a constructor overload that takes the value to be stored in A.
var obj = new Bar("Foo");
If I understand you right, you would like to the a, b, c and d properties to be initialized with the given values before the constructor runs. Unfortunately, that is not possible this way, because the default constructor always runs before the object intializers.
I advise you to do something like this instead:
class TestFixture
{
//... properties
public TestFixture()
{
this.init();
}
public TestFixture(string a, int b, int c, string d)
{
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.init();
}
private void init()
{
e= dosomething(a, b);
f= false;
g = DateTime.Now.ToString("yyMMddhhmmss");
h= TestName.Equals("1") && b.Equals("2") ? 1000 : 1;
i= 10000000;
j= a.Equals("FOT");
k = false;
}
}
This way you can init the a, b, c and d properties before the other initializer code runs.

Categories

Resources