How to implement instance numbering? - c#

I don't know if the title is clear but basically I am trying to implement something like this:
public class Effect
{
public int InternalId ...
public void ResetName() ...
}
When ResetName is called, this will reset the name of the object to:
"Effect " + someIndex;
So if I have 5 instances of Effect, they will be renamed to:
"Effect 1"
"Effect 2"
"Effect 3"
...
So I have another method (ResetNames) in another manager/container type that calls ResetName for each instance. And right now I have to pass an integer to ResetName while keeping a counter myself inside ResetNames. But this feels not as clean and this prevents me from calling ResetName myself outside the manager class, which is valid.
How to do this better/cleaner?
As for the InternalId, it's just some id that stores the creation order for everything. So I can't just rely on these, because the numbers are large, like 32000, etc.
EDIT: Container ResetNames code:
int count = 1;
var effects = this.Effects.OrderBy ( n => n.InternalId );
foreach ( Effect effect in effects )
{
effect.ResetName ( count );
++count;
}

Have a manager class that handles the naming. It will also handle creation of the child class, and will embed a reference to itself. You can now call ResetName() on the child class, and it will have it's manager handle whatever logic needs to be done.
I'm not sure exactly what you want the results to be in various situations, but hopefully the following will be of some help:
public class Effect {
{
private EffectManager _manager;
public string Name {get;set;}
public Effect(EffectManager manager) {
_manager = manager;
}
public void ResetName() {
Name = _manager.GetNextName();
}
}
public class EffectManager {
private List<Effect> Effects;
private int currentIndex;
public Effect CreateEffect() {
var e = new Effect(this);
Effects.Add(e);
}
public string GetNextName() {
return "Effect " + currentIndex++;
}
public void ResetAllNames() {
currentIndex = 0;
foreach(var effect in Effects) {
effect.Name = GetNextName();
}
}
}

One of many possibilities: give your Effect class a public property Name, and in the method where you populate a list or array of Effect objects, assign the name. You can also give the Effect class an integer property and set the number, so that you can sort them, if you want.
public class Effect()
{
public string Name() { get; set; }
}
public class SomeClass()
{
private List<Effect> Effects;
public static void WhateverMethod()
{
for (var i = 0; i < Effects.Count; i++)
Effects[i].Name = "Effect " + (i + 1).ToString();
}
}

Are the names specific to all instance or to all instances in a given collection?
If the former you could do something like:
public class Effect
{
private static int _lastId;
public Effect()
{
InternalId = _lastId++;
}
public string Name
{
get { return "Effect" + InternalId.ToString(); }
}
public int InternalId ...
}

Namespace Diagnostics
<Conditional("DEBUG")> _
Public NotInheritable Class UniqueID
Private Shared _idBase As Integer
Private Sub New()
'keep compiler from creating default constructor
End Sub
Public Shared Function GetNext() As String
Return "ID" + System.Threading.Interlocked.Increment(_idBase).ToString("00")
End Function
End Class
End Namespace

Instead of having Name be a stored property, could you do something like this?
public class Effect
{
public int InternalId ...
public int Index;
public string BaseName;
public string Name
{
get
{
return BaseName + index;
}
}
}

Related

how to protect static int in C#

I am learning C# so I am still on the basics here. This is my code
class foo
{
protected int id;
protected string data;
static int nextId = 1;
public int Id
{
get { return id; }
}
public foo()
{
this.id = nextId++;
}
public foo(string somedata)
{
this.data = somedata;
this.id = nextId++;
}
}
This code works just fine for now. All objects will have a unique ID with them.
Problem is: I don't want the first ID to be 1, I want it to be the number on the first line of the file given as an argument to the application from the commandline. If no file is specified or the file does not exist, then it can be one. Is there a way to make a one-time method to set nextId so it cannot be tampered with outside of the class after it has been once set?
Duh... I guess this is the trick. Still, I'd like to know if there is some build in way to make variables that can only be set once.
public int nextId
{
set {if(nextId<1) nextId = value;}
}
You can implement static constructor, which assigns proper value to nextId before first usage of foo class:
using System.IO;
using System.Linq;
...
class foo
{
...
static int nextId;
// read-only property which however can be assigned in the constructor
public int Id {get;}
// This static costructor will be called once before 1st usage of foo class
static foo() {
//TODO: put the right file name here
string fileName = Environment.GetCommandLineArgs()[1];
nextId = int.Parse(File
.ReadLines(fileName)
.First());
}
public foo()
{
//Let's increment nextId in thread-safe manner
Id = Interlocked.Increment(ref nextId);
}
...
}
You can do this
class foo
{
private static int nextId = 1;
private static bool isNextIdSet;
public SetId(newId)
{
if (!isNextIdSet) nextId = newId;
isNextIdSet = true;
}
}
So the nextId can be set only once from outside the class.
UPDATE: if you prefer to use this with many variables, you can create a helper for this, such as
class SetOnlyOnce<T>
{
private bool isSet;
public T Value
{
get;
set
{
if (!isSet) Value = value;
isSet = true;
}
}
}
Then use it as
class Foo
{
public SetOnlyOnce<int> prop1 {get;set;}
public SetOnlyOnce<string> prop2 {get;set;}
}
class Bar
{
public Bar()
{
var foo = new Foo();
foo.prop1.Value = 2;
foo.prop1.Value = 3; // this doesn't set.
}
}
As an alternative to Dmitry's answer, you can define the initialization through a static method. I prefer avoiding static constructors unless multiple fields need to be initialized simultaneously.
using System.IO;
using System.Linq;
...
class foo
{
...
// The initialization will be called at some time before first use of nextId.
private static int nextId = GenerateInitialNextId();
// read-only property which however can be assigned in the constructor
public int Id {get;}
private static int GenerateInitialNextId() {
//TODO: put the right file name here
string fileName = Environment.GetCommandLineArgs()[1];
return int.Parse(File
.ReadLines(fileName)
.First());
}
public foo()
{
//Let's increment nextId is thread-safe manner
Id = Interlocked.Increment(ref nextId);
}
...
}

Method overrides and polymorphysm

I am trying to create a program that allows the user to check into a hotel room. The program should check if the room is free and then allocate one of the free rooms if any are available. I have multiple rooms types such as a single room, a double room, a twin room and so on which all need to inherit from the base class Room.
Here is my code currently.
public class Room
{
public static bool[] av = { false, true, false };
public bool availability()
{
bool a = false;
foreach (var roomAv in av)
{
a = a || roomAv;
}
return a;
}
public bool availability(int room)
{
return av[room];
}
public int allocate()
{
if (availability())
{
int room = 0;
while (!av[room])
{
room++;
}
av[room] = false;
return room;
}
else
{
return -1;
}
}
public static void roomStatus()
{
for (int i = 0; i < av.Length - 1; i++)
{
Console.WriteLine(i + av[i].ToString());
}
}
}
class SingleRoom
{
}
The functions I have defined in the room class need to be usable by all the different room types but each hold their own separate array stating whether they are available or not. How can I do this? How can I access those functions for each class but on there own separate array instead of performing them just on the 'av' array like I have currently.
As you said you are new to C#, I would suggest to rethink on structure. You are in object-oriented paradigm. What you are thinking is plain old C-function oriented programming.
public class Room
{
public bool IsAvailable {get; set;}
public RoomType RoomType {get; set;}
public int RoomNo {get; set;}
public int Floor {get; set;}
public string RoomName {get; set;}
}
public enum RoomType
{
Single,
Double,
Twin,
King,
HoneymoonSuite
}
public class RoomManager
{
public List<Room> AllRooms {get; set;}
public RoomManager()
{
AllRooms = new List<Room>();
AllRooms.Add(new Room(){ RoomType=RoomType.Single,
RoomNo=1,
Floor=1,
RoomName="A101",
IsAvailable=true});
AllRooms.Add(new Room(){ RoomType=RoomType.Double,
RoomNo=2,
Floor=1,
RoomName="A102",
IsAvailable=false});
AllRooms.Add(new Room(){ RoomType=RoomType.HoneyMoonSuite,
RoomNo=1,
Floor=2,
RoomName="A201",
IsAvailable=true});
}
public bool IsAvailable(int roomNo)
{
//You need to check if roomNo is a valid RoomNo
return AllRooms.Any(r=>r.RoomNo==roomNo && r.IsAvailable);
}
public bool IsAvailable(string roomName)
{
//You need to check if roomName is valid RoomName
return AllRooms.Any(r=>r.RoomName==roomName && r.IsAvailable);
}
}
The functions i have defined in the room class need to be usable by
all the different room types but each hold their own separate array
stating whether they are available or not. how can i do this?
When you use the static keyword for a variable, you're saying the variable belongs to the type itself instead of the object instance. Quoting from MSDN Docs:
Use the static modifier to declare a static member, which belongs to
the type itself rather than to a specific object.
In other words, your array is "owned" by the class Room, not by individual objects of type Room created with new. If you want each object instance to own its own private member variables, then the static keyword needs to be removed. I.e.
public static bool[] av = { false, true, false };
should be:
public bool[] av = { false, true, false };
Note that the same applies to method names, i.e., if you use the static keyword on a method, the method is "owned" by the class/type itself, and not the individual object instances. This means, your roomStatus method must be used as Room.roomStatus() and trying new Room().roomStatus() would not be possible.
I'd actually recommend that you remove the array and turn this into a property, so that you can simply do something like:
Room r = new SingleRoom();
if(r.IsAvailable)
{
// ...
}
You should also refactor your code to follow .NET naming conventions for your methods, variable names, and make better use of object-orientation. I think Niraj Doshi's post is a good step in that direction.
Since you're new to C#, I'd recommend you get a hold of the book Effective C# by B. Wagner.
Update - Refactored Code
This is my take on refactoring the code, having a RoomManager, a IRoom interface, an abstract implementation of the IRoom interface called Room with code and functionality common to all rooms, a concrete SingleRoom for a more specific type, and a TextView class to manage how the data will be presented/displayed to the user (i.e. text-based output).
Notice that this following the Model-View-Controller (MVC) design pattern, with the Room classes being the models (i.e. data), the TextView being responsible for displaying the data (i.e. presentation), and the Main program itself being the controller (i.e. coordinating the other two).
Main Program
The program simply adds some rooms and then displays information for each of them, based on the manager's capacity.
using System;
using System.Collections.Generic;
namespace HotelRoomManager
{
class MainClass
{
public static void Main (string[] args)
{
RoomManager mgr = new RoomManager (5);
for (uint i = 0; i < mgr.Capacity; ++i)
mgr.AddRoom (new SingleRoom (1, i + 1) );
List<IRoom> rooms = mgr.GetAllRooms ();
TextView view = new TextView ();
view.RenderHeader ();
view.RenderModels (rooms);
mgr.RemoveAllRooms ();
}
}
}
IRoom Interface
The interface defines a type and is the basis for all the rooms. Interfaces are used to define contracts with clients, and does not rely on implementation details, which makes it a good object-oriented practice.
using System;
namespace HotelRoomManager
{
public enum BedType
{
Single,
Double,
Twin,
Queen,
King
}
public interface IRoom
{
BedType BedType { get; }
uint Floor { get; }
uint Number { get; }
bool IsOccupied { get; set; }
}
}
Abstract Room
The room simply contains code that is common to all rooms, regardless of their own individual details.
using System;
namespace HotelRoomManager
{
public abstract class Room : IRoom
{
private uint floor;
private uint number;
private bool occupied;
public Room (uint floor, uint number)
{
this.floor = floor;
this.number = number;
occupied = false;
}
public uint Floor {
get { return floor; }
}
public uint Number {
get { return number; }
}
public abstract BedType BedType { get; }
public bool IsOccupied {
get { return occupied; }
set { occupied = value; }
}
override public string ToString() {
return "Room(floor=" + floor + ", number=" + number + ")";
}
}
}
Concrete SingleRoom
By this point, this room only needs to report its actual type. It doesn't need to do anything special in addition to the common functionality already available.
using System;
namespace HotelRoomManager
{
public sealed class SingleRoom : Room
{
public SingleRoom (uint floor, uint number) : base(floor, number)
{}
override public BedType BedType {
get { return BedType.Single; }
}
}
}
The RoomManager
The manager simply helps to keep track of all the rooms and provides a simplified interface to interact with the collection.
using System;
using System.Collections.Generic;
namespace HotelRoomManager
{
public class RoomManager
{
private List<IRoom> rooms;
public RoomManager (uint capacity) {
rooms = new List<IRoom> ();
rooms.Capacity = (int) capacity;
}
public void AddRoom(IRoom room) {
rooms.Add (room);
}
public void RemoveRoom(IRoom room) {
rooms.Remove (room);
}
public List<IRoom> GetAllRooms() {
return rooms;
}
public void RemoveAllRooms() {
rooms.Clear ();
}
public uint Capacity {
get { return (uint) rooms.Capacity; }
}
}
}
The TextView
The sole responsibility of the view is to decide how the data from the models will be presented to the user. This decouples the data itself from how the data is displayed, making your system easier to maintain and expand. You can also have multiple views available instead of having to choose between one or the other.
using System;
using System.Collections.Generic;
using System.Text;
namespace HotelRoomManager
{
public class TextView
{
public TextView () {}
public void RenderHeader() {
Console.WriteLine ("Hotel Management System");
Console.WriteLine ("-----------------------");
}
public void RenderModels(List<IRoom> rooms) {
StringBuilder sb = new StringBuilder ();
foreach (IRoom r in rooms) {
sb.Append ("Floor : " + r.Floor + "\n");
sb.Append ("Number : " + r.Number + "\n");
sb.Append ("Bed : " + r.BedType + "\n");
sb.Append ("Occupied: " + (r.IsOccupied ? "Yes" : "No") + "\n\n");
}
Console.WriteLine (sb.ToString ());
}
}
}
Output
A quick run of the program will produce the following output:
Hotel Management System
-----------------------
Floor : 1
Number : 1
Bed : Single
Occupied: No
Floor : 1
Number : 2
Bed : Single
Occupied: No
Floor : 1
Number : 3
Bed : Single
Occupied: No
Floor : 1
Number : 4
Bed : Single
Occupied: No
Floor : 1
Number : 5
Bed : Single
Occupied: No
This is pretty simple, instead of a field, use a property:
public class Room
{
public virtual bool[] av { get; set; } = { false, true, false };
//All of your functions remain unchanged except you need to remove static
}
Then in your derived classes:
public class SingleRoom : Room
{
public override bool[] av { get; set; } = { true, true, false };
}
The inherited rooms will set the array which will be used in the base functions for availability so you only have to write it once.
This is another plus of properties over fields, where you can set a property such that it can be inherited. The only thing that was really "wrong" with your original code was that the array and some methods were declared static meaning that it was the same across all instances of the class. Availability should be an instance-level field/property, not a type-level one.
Your original code could work if you remove the static and made your derived classes like this:
public class SingleRoom
{
public SingleRoom
: base()
{
//Redefine the values of the array.
av = { true, true, false };
}
}
You put the array as static, meaning that all access to the array reaches the same object.
Remove that and each will have their own.
As per comments - the static identifier should be removed from the roomStatus method as well.

Too many calculated properties in my class

I have class which have too many related calculated properties.
I have currently kept all properties are read only.
some properties need long calculation and it is called again when its related properties are needed.
How can create this complex object .Also i want these properties should not be set from external code. I need show hide as i am binding properties for UI. Also i think order is also important.
My Class is something like
public string A
{
get
{
return complexMethod();
;
}
}
public string B
{
get
{
if (A == "value")
return "A";
else return "B";
;
}
}
public bool ShowHideA
{
get
{
return string.IsNullOrEmpty(A);
;
}
}
public bool ShowHideB
{
get
{
return string.IsNullOrEmpty(B);
;
}
}
public string complexMethod()
{
string value = "";
// calculation goes here
return value;
}
}
Thanks
You need to use Lazy type provided by .net:
Lazy<YourType> lazy = new Lazy<YourType>();
Make your properties internal to not be set from external code.
Well tall order isn't it?
One of the coolest things about extension methods is you can use types. This is perfect for writing external programs to calculate property values. Start like this...
public static class XMLibrary
{
public static MC CalculateValues(this MC myclass)
{
//for each property calculate the values here
if (myclass.Name == string.Empty) myclass.Name = "You must supply a name";
if (myclass.Next == 0) myclass.Next = 1;
//when done return the type
return myclass;
}
}
public class MC
{
public string Name { get; set; }
public int Next { get; set; }
}
public class SomeMainClass
{
public SomeMainClass()
{
var mc = new MC { Name = "test", Next = 0 };
var results = mc.CalculateValues();
}
}
There are many other ways to do class validation on a model, for example dataannotations comes to mind, or IValidatableObject works too. Keeping the validation separate from the class is a good idea.
//Complex properites are simple
public class MyComplextClass{
public List<MyThings> MyThings {get;set;}
public List<FileInfo> MyFiles {get;set;}
public List<DateTime> MyDates {get;set;}
}

Incrementing a unique ID number in the constructor

I'm working on an object in C# where I need each instance of the object to have a unique id. My solution to this was simply to place a member variable I call idCount in the class and within the constructor I would have:
objectID = idCount;
idCount++;
I thought that this would solve my problem but it seems that idCount never gets incremented even though the constructor gets called multiple times. For example if idCount = 1, the objectID for all the objects are still 1. Why doesn't idCount++ work?
Any help would be appreciated. Apologies if my explanation isn't adequate, I'm not sure how else to explain it.
You need a static property in your class, BUT, you need to assign it to an instance variable within the class if you want each object to contain the id it was created with.
Also, you'll want to use Interlocked.Increment on the counter in case you are updating multiple instances simultaneously:
public class Foo
{
private static int m_Counter = 0;
public int Id { get; set; }
public Foo()
{
this.Id = System.Threading.Interlocked.Increment(ref m_Counter);
}
}
You could use a static variable in your class that gets updated when the object is initialized.
public class Foo
{
private static int ID = 0;
private int myId = 0;
public int MyId
{
get { return myId; }
}
public Foo()
{
ID++;
this.myId = ID;
}
}
As everyone has pointed out, static variables are the specific answer to your question. But static variables only have scope within the process in which they were created and there is no relationship across processes (for example, a load balanced web environment).
If what you are looking for is a unique way to identify an object instance for the duration of its lifetime, I suggest something like:
byte[] bytes = new byte[8];
RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
crypto .GetBytes( bytes );
long id = BitConverter.ToInt64( bytes, 0 );
This will give you a random number which has an extremely low (roughly 0-1 in 100,000,000) chance of collision and you don't need to worry about keeping track of it.
You set IdCount is static member of MyObject.
public class MyObject
{
static int idCount = 0;
private int _objectID;
public int ObjectID
{
get { return _objectID; }
}
public MyObject()
{
idCount++;
_objectID = idCount;
}
}
public sealed class SingletonIdGenerator
{
private static long _id;
private SingletonIdGenerator()
{
}
public string Id
{
get { return _id++.ToString().Substring(8); }
}
public static SingletonIdGenerator Instance { get { return Nested.instance; } }
private class Nested
{
static Nested()
{
_id = DateTime.Now.Ticks;
}
internal static readonly SingletonIdGenerator instance = new SingletonIdGenerator();
}
}

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