Problem with struct and property in c# - c#

in a file I defined a public struct
public struct mystruct
{
public Double struct1;
public Decimal struct2;
}
In another I tried to do this:
class Test
{
mystruct my_va;
public mystruct my_va
{
get { return my_va; }
set { my_va = value; }
}
public Test()
{
my_va.struct1 = 10;
}
}
Intellisense recognizes My_va.struct1 but compiler says
Error 1 Cannot modify the return value
of 'TEST.mystruct' because it is not a
variable
How to correct the syntax ?

Yup, it's absolutely right. You see, when you fetch My_va, you're fetching a value - a copy of the current value of my_va. Changing that value would have no benefit, because you'd be immediately discarding the copy. The compiler is stopping you from writing code which doesn't do what it looks like it does.
In general, avoid mutable structs. They're evil. In this case, you could (for example) change mystruct to be immutable, but with a method like this:
public mystruct WithStruct1(double newValue)
{
return new mystruct(newValue, struct2);
}
then change your constructor code to:
My_va = My_va.WithStruct1(10);
... although in this case it's far more likely (given that you're in a constructor) that you should be writing:
My_va = new mystruct(10, 0);
Not only should structs be immutable, they should be pretty rare in most codebases, IMO. Other than for Noda Time, I've hardly ever written my own custom values types.
Finally, please learn the .NET naming conventions and try to follow them, even for sample code :)

It is highly recommended to avoid mutable structs. They exhibit all sorts of surprising behaviour.
Solution: Make your struct immutable.
public struct MyStruct
{
public readonly double Value1;
public readonly decimal Value2;
public MyStruct(double value1, decimal value2)
{
this.Value1 = value1;
this.Value2 = value2;
}
}
Usage:
class Test
{
private MyStruct myStruct;
public Test()
{
myStruct = new MyStruct(10, 42);
}
public MyStruct MyStruct
{
get { return myStruct; }
set { myStruct = value; }
}
}

I work with a list of structs, and solved this in a different way.
struct Pixel
{ Public int X;
Public int C;
}
List<Pixel> PixelList = new List<Pixel>
TempPixel = new Pixel();
Now when i want to set a value i code like this :
TempPixel = PixelList[i];
TempPixel.X= 23; // set some value
PixelList[i] = TempPixel
The code looks a bit strange perhaps, but it resolves the issue .
It solves the problem that a struct cannot be directly assigned a single value, but can be a copy of a similar type.
solving error CS1612:
https://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k%28CS1612%29;k%28TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV2.0%22%29;k%28DevLang-CSHARP%29&rd=true

Simplest fix: Change the struct to a class.

Unfortunately this error can be incorrectly generated when assigning to a property (i.e. invoking a property setter). An immutable struct can still have a valid property setter, as long as the property setter doesn't actually assign to any fields in the struct. For example,
public struct Relay
{
public Relay(Func<string> getText, Action<string> setText)
{
this.GetText = getText;
this.SetText = setText;
}
private readonly Func<string> GetText;
private readonly Action<string> SetText;
public string Text {
get { return this.GetText(); }
set { this.SetText(value); }
}
}
class Example
{
private Relay Relay {
get { return new Relay(() => this.text, t => { this.text = t; }); }
}
private string text;
public Method()
{
var r = new Relay();
r.Text = "hello"; // not a compile error (although there is a null reference)
// Inappropriately generates a compiler error
this.Relay.Text = "hello";
r = this.Relay;
r.Text = "hello"; // OK
}
}

Worth noting, that you can overcome this behavior by:
Implementing interface by struct: Struct : IStruct
Declare struct as field: Struct strExplicitly;
Example:
public interface IStruct
{
int Age { get; set; }
}
public struct Struct : IStruct
{
public int Age { get; set; }
}
public class Test
{
IStruct strInterface { get; set; }
Struct strExplicitly;
public Test()
{
strInterface = new Struct();
strExplicitly = new Struct();
}
public void ChangeAge()
{
strInterface.Age = 2;
strExplicitly.Age = 2;
}
}

Related

How to make sure object is properly initialized without constructor?

I would have to create a constructor with great amount of parameters like:
new MyClass(param1, param2, param3, ..., param100);
Is there any way to initialize object like that in a gradual manner, like:
MyClass obj = new MyClass();
obj.Prop1 = val1;
obj.Prop2 = val2;
obj.checkIfInit() //I am not sure how to do that.
How to verify that it is initialized properly if the crazy constructor is not used?
It seems there is a high amount of repetition in your constructor, which is almost always an indicator of bad design. If possible, why not use a collection type, like an array:
new MyClass(paramArray);
Nice and clean.
If you really need that much parameters, you can usually group them together in categories. Make classes for each of them and pass those instances in. It will make use later on much easier too.
As others have pointed out, you should really not have a constructor with so many parameters - although with Dependency Injection for a data model type class, you do often end up with a lot of parameters. In that case, it's usually best to group the parameters into subsets encapsulated into their own classes.
Notwithstanding that advice, you can address the issue with a variant of the "Builder Pattern".
For example, given:
public sealed class MyClass
{
public MyClass(int prop1, string prop2, DateTime prop3)
{
Prop1 = prop1;
Prop2 = prop2;
Prop3 = prop3;
}
public int Prop1 { get; }
public string Prop2 { get; }
public DateTime Prop3 { get; }
}
First note that it has no default constructor and the properties are all read-only, making this class immutable (often a good idea).
(I have omitted parameter checking for brevity.)
Now you can write a helper class to build the object:
public sealed class MyClassBuilder
{
public MyClass Build()
{
if (!_prop1Set || !_prop2Set || !_prop3Set)
throw new InvalidOperationException("Not all properties set.");
return new MyClass(_prop1, _prop2, _prop3);
}
public MyClassBuilder Prop1(int value)
{
_prop1 = value;
_prop1Set = true;
return this;
}
public MyClassBuilder Prop2(string value)
{
_prop2 = value;
_prop2Set = true;
return this;
}
public MyClassBuilder Prop3(DateTime value)
{
_prop3 = value;
_prop3Set = true;
return this;
}
int _prop1;
string _prop2;
DateTime _prop3;
bool _prop1Set;
bool _prop2Set;
bool _prop3Set;
}
Each method for setting a property returns this, to enable fluent use like so:
var builder = new MyClassBuilder();
builder
.Prop1(1)
.Prop2("test")
.Prop3(DateTime.Now);
var myClass = builder.Build(); // Throws if not all properties set.
This gives you a great deal of flexibility for parameter validation and allowing some parameters to be omitted (by providing suitable defaults).
A real-world example of a builder class is Autofac's ContainerBuilder class, usage of which is described here.
Make all paramter to a class or struct , to help you make controctor be clean.
public class InitData
{
Parmter ....
}
new MyClass(InitData data);
Or use paramters
public class MyClass
{
public MyClass(params[] paramters)
{
foreach(p in paramters)
{ ... }
}
}
Possbie do not make a 'crazy controcter' is best soultion I think.
You can override Equals in order to check the default value:
public class MyClass {
public static readonly MyClass DefaultInstance = new MyClass();
public int Val1 { get; set; }
public int Val2 { get; set; }
// Etc...
public MyClass() {
this.Val1 = 10;
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + Val1.GetHashCode();
hash = hash * 23 + Val2.GetHashCode();
return hash;
}
}
public override bool Equals(Object obj) {
if (obj == this)
{
return true;
}
var other = obj as MyClass;
return other?.Val1 == this.Val1 &&
other?.Val2 == this.Val2;
// Etc...
}
}
Then you can just check using:
if (MyClass.DefaultInstance.Equals(instanceToCheck)) {
... // All defaults
}
C# compiler implicitly gives you a default constructor if you are not writing any Constructor for a class.
Now, If you are explicitly giving an Constructor now the C# Compiler will not provide you any Constructor.
i.e you have only One Constructor with you =>MyClass(param1, param2, param3, ..., param100);
Now, You are trying to Create the object without any Parameters.=>MyClass obj = new MyClass();
So, there will be error every time you compile as the Compiler does not find this type of empty overload of the Constructor which one is not taking any value.
To avoid this use an empty constructor explicitly.
Look for the Following example.
Class1 cs = new Class1();
cs.x = "xyz";
cs.y = "zyx";
if(cs!=null)
{
//This checks the Object is created or not i.e Reference is created.
Console.Write("I'm intialized");
}
else
{
Console.WriteLine("I'm not initialized");
}
And the Class for Class1 follows
class Class1
{
public string x;
public string y;
public Class1(string x,string y)
{
this.x = x;
this.y = y;
}
public Class1()
{
}
}
Check it.

C# Use int constants vs Enums without cast

I have some int constants grouped in several Enum, like:
enum myEnum{
OBJECT_A = 10, OBJECT_B = 13 };
Now I have several functions which take this Enums and do something, like:
void myfunc(myEnum e)
{ .... }
In my code, I need to use myfunc in both these two ways:
myfunc(myEnum.OBJECT_A);
myfunc(13);
This gives an error because ints aren't casted to Enum implicitly.
What do you recommend as a best practice to do this preserving readability of the code?
An obvious solution is to use myfunc((myEnum)13); but this is boring because one needs to cast the int every time and the code gets heavy.
So far what I did is (avoiding enums at all):
using EChannelInt = System.Int32;
public static class EChannel
{
public static readonly int CH_CONNECTION = 10;
public static readonly int CH_DATA = 50;
}
public void doit(EChannelInt ch)
{ .... }
doit(EChannel.CH_DATA);
doit(10);
which works, but I don't like it very much because it seems like a "trick" or renaming thigs. What do you suggest? Perhaps "implicit operator" may be useful?
You can overload myFunc:
void myFunc(int i)
{
myFunc((myEnum)i);
}
You can use type-safe-enum pattern and you can override the implicit cast operator.
public class EChannel
{
public int Value {get; private set;};
public static readonly EChannel CH_CONNECTION = new EChannel(10);
public static readonly EChannel CH_DATA = new EChannel(50);
private EChannel(int value)
{
Value = value;
}
public static implicit operator EChannel(int a)
{
EChannel eChannel = null;
switch (a) // this need to be changed to something more light
{
case 10:
eChannel = CH_CONNECTION;
break;
case 50:
eChannel = CH_DATA;
break;
default:
throw new Exception("Constant don't exists");
}
return eChannel;
}
}
And you use it like this
public void doit(EChannel ch)
{ .... }
doit(EChannel.CH_DATA);
doit(10);
How about an overload?
void myfunc(int i)
{
myfunc((myEnum)i);
}
(If you don't have control of the class, you can do it as an extension method.)
I would stick with the enumeration values as much as possible and only cast to int in a narrow scope when absolutely necessary (if at all).
However, if you insist on mixing integers and enumeration values then you should consider defining the enum members from the integers so that they are guaranteed to be consistent.
Example:
public static class EChannel
{
public const int CH_CONNECTION = 10;
}
public enum myEnum
{
CH_CONNECTION = EChannel.CH_CONNECTION
}

"Read-only" public properties without setters/getters

Does C# have such a feature (like Python's getter-only pattern)?
class A
{
public [read-only] Int32 A_;
public A()
{
this.A_ = new Int32();
}
public A method1(Int32 param1)
{
this.A_ = param1;
return this;
}
}
class B
{
public B()
{
A inst = new A().method1(123);
Int32 number = A.A_; // okay
A.A_ = 456; // should throw a compiler exception
}
}
To obtain this I could use the private modifier on the A_ property, and only implement a getter method. Doing so, in order to access that property I should always make a call to the getter method... is it avoidable?
Yes that is possible, syntax is like this:
public int AProperty { get; private set; }
yes. you can use read only property with private setter.
Using Properties - msdn
public string Name
{
get;
private set;
}

Overriding the Defaults in a struct (c#)

Is it possible to set or override the default state for a structure?
As an example I have an
enum something{a,b,c,d,e};
and a structure that links 2 values for that enum
struct SomethingData
{
something type;
int Value;
double Multipler;
SomethingData(something enumVal, int intVal, double DblVal) {...}
}
But can I specify that the default state is
SomethingData(something.c,0,1);
Struct constructors are similar to
class constructors, except for the
following differences:
Structs cannot contain explicit
parameterless constructors. Struct
members are automatically initialized
to their default values. A struct
cannot have an initializer in the
form: base (argument-list).
http://msdn.microsoft.com/en-us/library/aa288208(v=vs.71).aspx
So, short answer, no you can't override the default constructor (every struct has a parameterless constructor and you can't hide it or override it)...
You can't. Structs always have a default constructor that sets every member to its default value (null for reference types, 0 for numeric types, false for bools, etc.) This behavior cannot be changed.
You can't override the default (parameterless) constructor for a struct. You can only add new constructors, which take parameters.
http://csharp.2000things.com/2010/10/03/108-defining-a-constructor-for-a-struct/
Creating a class object will cause all of the instance fields to come into existence before anything--even the class constructor--can access it, and allocating an array will cause all of its elements to exist before anything can access the array. Both of these actions will cause all of the memory allocated to those fields or elements to be zeroed out without regard for the data types to be stored therein.
When a class-type storage location comes into existence, it will initially hold a null reference. When a structure-type storage location comes into existence, all of its fields (and any fields of structures within it) will do so simultaneously. Unlike class object instances which can only come into existence by using a constructor, structure-type storage locations are brought into existence without using any of the structure's own code. Consequently, the structure's definition will have no say in what should happen when "instances" [i.e. struct-type storage locations] come into existence.
A struct is, fundamentally, a collection of fields bound together with duct tape. If a struct is supposed to behave like something else, it should typically make its fields private and pretend to be immutable [even though struct assignment actually mutates the destination struct by overwriting all its fields with the corresponding values from the source, and the struct definition gets no say in the matter]. If, however, a struct is supposed to encapsulate a fixed set of related but independent values (e.g. the coordinates of a point), which may independently accommodate any combination of values which are legal for their respective types, a struct should simply expose its fields publicly. Some people may whine about "mutable structs are evil", but the evils only apply when invoking self-mutating methods on a struct. Structs which expose their state as fields behave like collections of variables stuck together with duct tape. If what one needs is a collection of variables stuck together with duct tape, trying to make a struct pretend to be immutable will simply make it harder to program with.
There is a workaround to make this happen by using custom Property getters. Observe:
public struct Foostruct
{
private int? _x;
private int? _y;
public int X
{
get { return _x ?? 20; } // replace 20 with desired default value
set { _x = value; }
}
public int Y
{
get { return _y ?? 10; } // replace 10 with desired default value
set { _y = value; }
}
}
This will only work for value types (which can be wrapped with nullable) but you could potentially do something similar for reference types by wrapping them in a generic class like below:
public class Wrapper<TValue>
{
public TValue Value { get; set; }
}
public struct Foostruct
{
private Wrapper<Tick> _tick;
public Tick Tick
{
get { return _tick == null ? new Tick(20) : _tick.Value; }
set { _tick = new Wrapper<Tick> { Value = value }; }
}
}
Somewhat related: I've often wanted to use the new object initializer syntax with an immutable value type. However, given the nature of a typical immutable value type implementation, there is no way to utilize that syntax, since the properties are read-only.
I've come up with this approach; In my opinion this still satisfies the immutability of the value type, but allows the code that is responsible for instantiating the value type greater control over the initialization of the internal data.
struct ImmutableValueType
{
private int _ID;
private string _Name;
public int ID
{
get { return _ID; }
}
public string Name
{
get { return _Name; }
}
// Infuser struct defined within the ImmutableValueType struct so that it has access to private fields
public struct Infuser
{
private ImmutableValueType _Item;
// write-only properties provide the complement to the read-only properties of the immutable value type
public int ID
{
set { _Item._ID = value; }
}
public string Name
{
set { _Item._Name = value; }
}
public ImmutableValueType Produce()
{
return this._Item;
}
public void Reset(ImmutableValueType item)
{
this._Item = item;
}
public void Reset()
{
this._Item = new ImmutableValueType();
}
public static implicit operator ImmutableValueType(Infuser infuser)
{
return infuser.Produce();
}
}
}
class Program
{
static void Main(string[] args)
{
// use of object initializer syntax made possible by the Infuser type
var item = new ImmutableValueType.Infuser
{
ID = 123,
Name = "ABC",
}.Produce();
Console.WriteLine("ID={0}, Name={1}", item.ID, item.Name);
}
}
Each time you get/set property you need to set default value call InitDefaultValues() method
private string _numberDecimalSeparator;
public string NumberDecimalSeparator
{
get
{
InitDefaultValues();
return _numberDecimalSeparator;
}
set
{
InitDefaultValues();
_numberDecimalSeparator = value;
}
}
...
private void InitDefaultValues()
{
if (!_inited)
{
_inited = false;
var ci = CultureInfo.CurrentCulture;
_numberDecimalSeparator = ci.With(x => x.NumberFormat).Return(x => x.NumberDecimalSeparator, ".");
...
}
}
Kinda dumb, but works
public readonly static float default_value = 1;
public struct YourStruct{
public float yourValue{
get {
return _yourValue + default_value;
}
set {
_yourValue= value - default_value;
}
}
public float _yourValue;
}
My solution. It works as well.
public struct DisplayOptions
{
public bool isUpon;
public bool screenFade;
public static DisplayOptions Build()
{
// Return default value
return new DisplayOptions(true, true);
}
DisplayOptions(bool isUpon, bool screenFade)
{
this.isUpon = isUpon;
this.screenFade = screenFade;
}
public DisplayOptions SetUpon(bool upon)
{
this.isUpon = upon;
return this;
}
public DisplayOptions SetScreenFade(bool screenFade)
{
this.screenFade = screenFade;
return this;
}
}
Use default value
// Use default
UIMaster.Instance.StartScreen("Screen 2", DisplayOptions.Build());
// Use custome
UIMaster.Instance.StartScreen("Screen 2", DisplayOptions.Build().SetScreenFade(false));
UIMaster.Instance.StartScreen("Screen 2", DisplayOptions.Build().SetUpon(false));
this should work
public struct MyStruct
{
private string myName;
private int? myNumber;
private bool? myBoolean;
private MyRefType myType;
public string MyName
{
get { return myName ?? "Default name"; }
set { myName= value; }
}
public int MyNumber
{
get { return myNumber ?? 42; }
set { myNumber = value; }
}
public bool MyBoolean
{
get { return myBoolean ?? true; }
set { myBoolean = value; }
}
public MyRefType MyType
{
get { return myType ?? new MyRefType(); }
set { myType = value; }
}
//optional
public MyStruct(string myName = "Default name", int myNumber = 42, bool myBoolean = true)
{
this.myType = new MyRefType();
this.myName = myName;
this.myNumber = myNumber;
this.myBoolean = myBoolean;
}
}
[TestClass]
public class MyStructTest
{
[TestMethod]
public void TestMyStruct()
{
var myStruct = default(MyStruct);
Assert.AreEqual("Default name", myStruct.MyName);
Assert.AreEqual(42, myStruct.MyNumber);
Assert.AreEqual(true, myStruct.MyBoolean);
Assert.IsNotNull(myStruct.MyType);
}
}
This may work...
public struct MyStruct
{
private bool _name;
public string myName
{
get { return (_name ? myName : "Default name"); }
set { _name = true; myName = value; }
}
private bool _num;
public int myNumber
{
get { return (_num ? myNumber : 42); }
set { _num = true; myNumber = value; }
}
private bool _bool;
public bool myBoolean
{
get { return (_bool ? myBoolean : true); }
set { _bool = true; myBoolean = value; }
}
private bool _type;
public MyRefType myType
{
get { return _type ? myType : new MyRefType(); }
set { _type = true; myType = value; }
}
}
Nevermind StackOverflowException
There is a workaround
public struct MyStruct
{
public MyStruct(int h = 1, int l = 1)
{
high = h;
low = l;
}
public int high;
public int low;
}

Call one constructor from another

I have two constructors which feed values to readonly fields.
public class Sample
{
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
_intField = i;
}
public Sample(int theInt) => _intField = theInt;
public int IntProperty => _intField;
private readonly int _intField;
}
One constructor receives the values directly, and the other does some calculation and obtains the values, then sets the fields.
Now here's the catch:
I don't want to duplicate the
setting code. In this case, just one
field is set but of course there may
well be more than one.
To make the fields readonly, I need
to set them from the constructor, so
I can't "extract" the shared code to
a utility function.
I don't know how to call one
constructor from another.
Any ideas?
Like this:
public Sample(string str) : this(int.Parse(str)) { }
If what you want can't be achieved satisfactorily without having the initialization in its own method (e.g. because you want to do too much before the initialization code, or wrap it in a try-finally, or whatever) you can have any or all constructors pass the readonly variables by reference to an initialization routine, which will then be able to manipulate them at will.
public class Sample
{
private readonly int _intField;
public int IntProperty => _intField;
private void setupStuff(ref int intField, int newValue) => intField = newValue;
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
setupStuff(ref _intField,i);
}
public Sample(int theInt) => setupStuff(ref _intField, theInt);
}
Before the body of the constructor, use either:
: base (parameters)
: this (parameters)
Example:
public class People: User
{
public People (int EmpID) : base (EmpID)
{
// Add more statements here.
}
}
I am improving upon supercat's answer. I guess the following can also be done:
class Sample
{
private readonly int _intField;
public int IntProperty
{
get { return _intField; }
}
void setupStuff(ref int intField, int newValue)
{
//Do some stuff here based upon the necessary initialized variables.
intField = newValue;
}
public Sample(string theIntAsString, bool? doStuff = true)
{
//Initialization of some necessary variables.
//==========================================
int i = int.Parse(theIntAsString);
// ................
// .......................
//==========================================
if (!doStuff.HasValue || doStuff.Value == true)
setupStuff(ref _intField,i);
}
public Sample(int theInt): this(theInt, false) //"false" param to avoid setupStuff() being called two times
{
setupStuff(ref _intField, theInt);
}
}
Here is an example that calls another constructor, then checks on the property it has set.
public SomeClass(int i)
{
I = i;
}
public SomeClass(SomeOtherClass soc)
: this(soc.J)
{
if (I==0)
{
I = DoSomethingHere();
}
}
Yeah, you can call other method before of the call base or this!
public class MyException : Exception
{
public MyException(int number) : base(ConvertToString(number))
{
}
private static string ConvertToString(int number)
{
return number.toString()
}
}
Constructor chaining i.e you can use "Base" for Is a relationship and "This" you can use for same class, when you want call multiple Constructor in single call.
class BaseClass
{
public BaseClass():this(10)
{
}
public BaseClass(int val)
{
}
}
class Program
{
static void Main(string[] args)
{
new BaseClass();
ReadLine();
}
}
When you inherit a class from a base class, you can invoke the base class constructor by instantiating the derived class
class sample
{
public int x;
public sample(int value)
{
x = value;
}
}
class der : sample
{
public int a;
public int b;
public der(int value1,int value2) : base(50)
{
a = value1;
b = value2;
}
}
class run
{
public static void Main(string[] args)
{
der obj = new der(10,20);
System.Console.WriteLine(obj.x);
System.Console.WriteLine(obj.a);
System.Console.WriteLine(obj.b);
}
}
Output of the sample program is
50 10 20
You can also use this keyword to invoke a constructor from another constructor
class sample
{
public int x;
public sample(int value)
{
x = value;
}
public sample(sample obj) : this(obj.x)
{
}
}
class run
{
public static void Main(string[] args)
{
sample s = new sample(20);
sample ss = new sample(s);
System.Console.WriteLine(ss.x);
}
}
The output of this sample program is
20
Error handling and making your code reusable is key. I added string to int validation and it is possible to add other types if needed. Solving this problem with a more reusable solution could be this:
public class Sample
{
public Sample(object inputToInt)
{
_intField = objectToInt(inputToInt);
}
public int IntProperty => _intField;
private readonly int _intField;
}
public static int objectToInt(object inputToInt)
{
switch (inputToInt)
{
case int inputInt:
return inputInt;
break;
case string inputString:
if (!int.TryParse(inputString, out int parsedInt))
{
throw new InvalidParameterException($"The input {inputString} could not be parsed to int");
}
return parsedInt;
default:
throw new InvalidParameterException($"Constructor do not support {inputToInt.GetType().Name}");
break;
}
}
Please, please, and pretty please do not try this at home, or work, or anywhere really.
This is a way solve to a very very specific problem, and I hope you will not have that.
I'm posting this since it is technically an answer, and another perspective to look at it.
I repeat, do not use it under any condition. Code is to run with LINQPad.
void Main()
{
(new A(1)).Dump();
(new B(2, -1)).Dump();
var b2 = new B(2, -1);
b2.Increment();
b2.Dump();
}
class A
{
public readonly int I = 0;
public A(int i)
{
I = i;
}
}
class B: A
{
public int J;
public B(int i, int j): base(i)
{
J = j;
}
public B(int i, bool wtf): base(i)
{
}
public void Increment()
{
int i = I + 1;
var t = typeof(B).BaseType;
var ctor = t.GetConstructors().First();
ctor.Invoke(this, new object[] { i });
}
}
Since constructor is a method, you can call it with reflection. Now you either think with portals, or visualize a picture of a can of worms. sorry about this.
In my case, I had a main constructor that used an OracleDataReader as an argument, but I wanted to use different query to create the instance:
I had this code:
public Subscriber(OracleDataReader contractReader)
{
this.contract = Convert.ToString(contractReader["contract"]);
this.customerGroup = Convert.ToString(contractReader["customerGroup"]);
this.subGroup = Convert.ToString(contractReader["customerSubGroup"]);
this.pricingPlan= Convert.ToString(contractReader["pricingPlan"]);
this.items = new Dictionary<string, Member>();
this.status = 0;
}
So I created the following constructor:
public Subscriber(string contract, string customerGroup) : this(getSubReader(contract, customerGroup))
{ }
and this method:
private static OracleDataReader getSubReader(string contract, string customerGroup)
{
cmdSubscriber.Parameters[":contract"].Value = contract + "%";
cmdSubscriber.Parameters[":customerGroup"].Value = customerGroup+ "%";
return cmdSubscriber.ExecuteReader();
}
notes: a statically defined cmdSubscriber is defined elsewhere in the code; My main constructor has been simplified for this illustration.
In case you need to run something before calling another constructor not after.
public class Sample
{
static int preprocess(string theIntAsString)
{
return preprocess(int.Parse(theIntAsString));
}
static int preprocess(int theIntNeedRounding)
{
return theIntNeedRounding/100;
}
public Sample(string theIntAsString)
{
_intField = preprocess(theIntAsString)
}
public Sample(int theIntNeedRounding)
{
_intField = preprocess(theIntNeedRounding)
}
public int IntProperty => _intField;
private readonly int _intField;
}
And ValueTuple can be very helpful if you need to set more than one field.
NOTE: most of the solutions above does not work for structs.
Unfortunately initializing struct fields in a method called by a constructor is not recognized by the compiler and will lead to 2 errors:
in the constructor: Field xxxx must be fully assigned...
in the method, if you have readonly fields: a read-only field cannot be assigned except in a constructor.
These can be really frustrating for example when you just need to do simple check to decide on which constructor to orient your call to.

Categories

Resources