Please first take a look at this simple code;
This is my base class:
public class BaseClass
{
public BaseClass()
{
}
public BaseClass(BaseClass b)
{
}
public virtual string GetMSG()
{
return "Base";
}
}
and this is the derived one:
public class DrivenClass : BaseClass
{
public string MSG { get; set; }
public DrivenClass(string msg)
{
MSG = msg;
}
public DrivenClass(DrivenClass d)
{
MSG = d.MSG;
}
public override string GetMSG()
{
return MSG;
}
}
and this is the test:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public BaseClass B { get; set; }
public DrivenClass D { get; set; }
private void button1_Click(object sender, EventArgs e)
{
D = new DrivenClass("Driven");
B = new BaseClass(D);
MessageBox.Show("B:" + B.GetMSG() + "\nD:" + D.GetMSG());
}
}
Now my question is what should I do that B = new BaseClass(D); works like B = new DrivenClass(D); ?
I'm using this in polymorphism and I like to use one copy-constructor instead of different driven ones.
I want the output like this :
Driven
Driven
but now it's like this :
Base
Driven
You can use an overridden virtual Copy method instead of a copy constructor.
public class BaseClass
{
public BaseClass()
{
}
public virtual BaseClass ShallowCopy()
{
return new BaseClass();
}
public virtual string GetMSG()
{
return "Base";
}
}
public class DrivenClass : BaseClass
{
public string MSG { get; set; }
public DrivenClass(string msg)
{
MSG = msg;
}
public override BaseClass ShallowCopy() {
return new DrivenClass(this.MSG);
}
public override string GetMSG()
{
return MSG;
}
}
Then call it like this:
D = new DrivenClass("Driven");
B = D.ShallowCopy();
This will work because calling a virtual method always calls the actual overriden implementation in the subclass, even when called from the baseclass interface.
What happens is normal because you create new instance of base class here. Therefore you never override the GetMSG method:
B = new BaseClass(D);
What you wanted to do is to have the same public class:
public BaseClass B { get; set; }
and to give it the value of new DrivenClass(D)
B = new DrivenClass(D);
Related
Here's what I have:
public partial class MainWindow : Window
{
IMainUIHandler MainUIHandler;
public MainWindow()
{
//InitializeComponent();
IMainUIHandler UIHandlerMain = new MainUIHandler();
UIHandlerMain.PlayerMgtHandler.AddNewPlayer("2020", "_", 1, 3);
... more stuff
}
}
class MainUIHandler : IMainUIHandler
{
public IPlayerMgtUIHandler PlayerMgtHandler { get; }
public MainUIHandler()
{
PlayerMgtHandler = new PlayerMgtUIHandler();
}
}
class PlayerMgtUIHandler : IPlayerMgtUIHandler
{
public List<IPlayer> NewPlayers { get; } //TODO change List to HashSet
public void AddNewPlayer(string idPrefix, string idSeparator, int idSeqNumber,int idNumDigits)
{
IPlayer player=new Player(idPrefix,idSeparator,idSeqNumber,idNumDigits);
NewPlayers.Add(player);
}
public PlayerMgtUIHandler()
{
List<IPlayer> NewPlayers = new List<IPlayer>();
}
}
Stepping through beginning at MainWindow from IMainUIHandler UIHandlerMain = new MainUIHandler();, when I get to:
public PlayerMgtUIHandler()
{
List<IPlayer> NewPlayers = new List<IPlayer>();
}
the List<IPlayer> NewPlayers is not nothing; it has zero elements. When I step out back to the caller PlayerMgtHandler.NewPlayers is null.
What am I doing wrong?
Changed class PlayerMgtUIHandler to:
class PlayerMgtUIHandler : IPlayerMgtUIHandler
{
public List<IPlayer> NewPlayers { get; protected set; } //TODO change List to HashSet
public void AddNewPlayer(string idPrefix, string idSeparator, int idSeqNumber,int idNumDigits)
{
IPlayer player=new Player(idPrefix,idSeparator,idSeqNumber,idNumDigits);
NewPlayers.Add(player);
}
public PlayerMgtUIHandler()
{
NewPlayers = new List<IPlayer>();
}
}
Now it works as I wanted. Thanks for pointing me in the right direction.
I have a class named PINPAD, a base class named Devices, and two derived classes named DevA and Dev B
The issue is that the main class property PINPAD.Status needs to be updated from classes DevA and DevB
Here is the code:
public class CALLER()
{
CALLER()
{
PINPAD PINPD = new PINPAD("A");
//....
MessageBox.Show(PINPD.Status);
}
}
public class PINPAD()
{
public Devices MyDev = null;
public string Status = "";
public PINPAD(string Model)
{
if (Model = "A")
{
DevA MyDev = new DevA()
}
else
{
DevB MyDev = new DevB()
}
MyDev.DoWork();
}
}
public class Devices
{
public virtual void DoWork() {}
}
public class DevA : Devices
{
public override void DoWork() { }
DevA()
{
PINPAD.Status = "Broken";
//Status not avialable!
}
}
public class DevB : Devices
{
public override void DoWork() { }
DevB()
{
PINPAD.Status = "Working!";
//Status not avialable!
}
}
You've declared PINPAD.Status as an instance field - meaning you have to have an object of the type PINPAD in order to access it.
var myPinpad = new PINPAD();
myPinpad.Status = "Whatever";
If you want there to just be one field that is available everywhere, declare the field static:
public static string Status = "";
I do not know if I understood something wrong. But Visual Studio says that adding an item does not allow the conversion from ExporterTaskWorker<ExporterTypeMusic> to ExporterTaskWorker<IExporterType>. But ExporterTypeMusic implements the IExporterType interface.
What am I doing wrong?
public interface IExporterType
{
bool BrandChannelAssigning();
}
public class ExporterTypeMusic : IExporterType
{
public bool BrandChannelAssigning()
{
throw new System.NotImplementedException();
}
}
public class ExporterTaskWorker<T> : INotifyPropertyChanged where T : IExporterType
{
public Config TheConfig { get; set; }
public object SomeProperty { get; set; }
...
...
public ExporterTaskWorker(Config _config) {
}
}
public class SomeClass
{
public ObservableCollection<ExporterTaskWorker<IExporterType>> ExporterInstanceCollection { get; set; } = new ObservableCollection<ExporterTaskWorker<IExporterType>>();
public void SomeMethod()
{
Config theConfig = new Config();
ExporterTaskWorker<ExporterTypeMusic> exporterTaskWorker = new ExporterTaskWorker<ExporterTypeMusic>(theConfig);
ExporterInstanceCollection.Add(exporterTaskWorker);
}
}
This question already has answers here:
Virtual member call in a constructor
(18 answers)
Closed 8 years ago.
Is it wrong to initialize a virtual property in the constructor? It just does not feel right because if you override the property in a derived class the property will first be initialized with the value from the base class constructor then it will be assigned again by the derived class constructor. is there an alternative for doing this? I'm talking about something like this
internal class B1
{
public B1()
{
Ti = "Hello";
}
public virtual string Ti { get; set; }
}
internal class B2 : B1
{
public B2()
{
Ti = "HelloKitty";
}
public override string Ti { get; set; } //<--"Hello" will be assigned first then "HelloKitty" will be assigned
}
internal class Program
{
private static void Main(string[] args)
{
var b2 = new B2();
Console.WriteLine(b2.Ti);
Process.GetCurrentProcess().WaitForExit();
}
}
UPDATE 1:
As recommended by #AK_
internal class Bb1
{
private string _ti;
public Bb1()
{
_ti = "Hello";
}
public virtual string Ti
{
get { return _ti; }
set { _ti = value; }
}
}
internal sealed class Bb2 : Bb1
{
public Bb2()
{
Ti = "HelloKitty";
}
public override string Ti { get; set; }
}
the variable _ti in the base class is initialized by "Hello".
what if instead of string type I'm using type which explicitly needs to be exposed?
On the other hand this is reasonable (notice that B2 is sealed )
internal class B1
{
private string m_ti;
public virtual string Ti { get{return m_ti;} set{m_ti = value;} }
public B1()
{
m_ti = "Hello";
}
}
internal sealed class B2 : B1
{
public B2()
{
Ti = "HelloKitty";
}
public override string Ti { get; set; } //<--"Hello" will be assigned first then "HelloKitty" will be assigned
}
another option a protected constructor:
internal class B1
{
private string m_ti;
public virtual string Ti { get { return m_ti; } set { m_ti = value; } }
public B1()
{
m_ti = "Hello";
}
protected B1(String word)
{
m_ti = word;
}
}
internal sealed class B2 : B1
{
public B2():base("kitty")
{
}
}
Imagine a class as follows.. It's a class provided to me to work with.. I cannot change its source..
public class MyClass
{
object _Object { get; set; }
public void FuncA1() { _Object = new object(); }
public void FuncA2() { _Object = new List<object>(); }
public int FuncB1() { _Object = 0; return 0; }
public int FuncB2() { _Object = 123; return 123; }
public string FuncC1() { _Object = null; return null; }
public string FuncC2() { _Object = "Hello"; return "Hello"; }
}
Im trying to create a wrapper for this class, such that I can group its many functions into categories..
MyWrapper.Voids.FuncA1();
MyWrapper.Voids.FuncA2();
MyWrapper.Integers.FuncB1();
MyWrapper.Integers.FuncB2();
MyWrapper.Strings.FuncC1();
MyWrapper.Strings.FuncC2();
The only solution I can think of for this scenario is to design the wrapper like this:
public class MyWrapper
{
MyClass _Instance { get; set; }
public _Void Voids { get; private set; }
public _Integer Integers { get; private set; }
public _String Strings { get; private set; }
public class _Void
{
MyWrapper _Parent { get; set; }
public void FuncA1() { _Parent._Instance.FuncA1(); }
public int FuncA2() { return _Parent._Instance.FuncA2(); }
}
public class _Integer
{
...
}
public class _String
{
...
}
public MyWrapper()
{
_Instance = new MyClass();
Voids = new _Voids(this);
Integers = new _Integer(this);
Strings = new _String(this);
}
}
This solution works, but has a number of problems:
- The inner classes are forced to be public, which allows them to be instantiated by the user..
- I am forced to maintain a reference of the parent object in the child classes..
Is there a better way of doing this?
EDIT: The code posted initially was a bit confusing, in the sense that it was diverting attention away from the core issue and more into the issues of whether a function would cause exceptions or not if they all work on the same object..
NOTE: This is not actual code.. I hacked together this example to show what I'm trying to do.. CREATE A WRAPPER AROUND AN OBJECT (I cannot change the original object's code) AND GROUP FUNCTIONS INTO CATEGORIES..
FINAL EDIT: following suggestion by Juharr.. here's what ive done to accomplish what i wanted.. for the betterment of others..
public interface IVoid
{
void FuncA1();
void FuncA2();
}
public interface IInteger
{
int FuncB1();
int FuncB2();
}
public class MyWrapper
{
public MyClass Instance { get; private set; }
public IVoid Voids { get; private set; }
public IInteger Integers { get; private set; }
private abstract class MyBase
{
protected MyWrapper Parent { get; set; }
protected MyClass Instance { get { return Parent.Instance; } }
public MyBase(MyWrapper oParent) { Parent = oParent; }
}
private class MyVoid : MyBase, IVoid
{
public MyVoids (MyWrapper oParent) : base(oParent) { }
public void FuncA1() { Instance.FuncA1(); }
public void FuncA2() { Instance.FuncA2(); }
}
private class MyInteger : MyBase, IInteger
{
public MyInteger (MyWrapper oParent) : base(oParent) { }
public int FuncB1() { return Instance.FuncB1(); }
public int FuncB2() { return Instance.FuncB2(); }
}
public MyWrapper()
{
Instance = new MyClass();
Voids = new MyVoid(this);
Integers = new MyInteger(this);
}
}
You could write public interfaces instead. Then your inner classes don't have to be public. So something like this.
public interface IIntger
{
void Set(int iValue);
int Get();
}
public class MyWrapper
{
MyClass _Instance { get; set; }
public IInteger Integer { get; private set; }
private class _Integer : IInteger
{
MyWrapper _Parent { get; set; }
public void Set(int iValue) { _Parent._Instance.IntegerSet(iValue); }
public int Get() { return _Parent._Instance.IntegerGet(); }
}
public MyWrapper()
{
_Instance = new MyClass();
Integer = new _Integer(this);
}
}
EDIT:
To answer the second part of your question you will either need the reference to the parent class or a reference to the class you are wrapping. So you could have this instead.
public class MyWrapper
{
public IInteger Integer { get; private set; }
private class _Integer : IInteger
{
MyClass _Instance { get; set; }
public _Integer(MyClass myClass) { _Instance = myClass; }
public void Set(int iValue) { _Instance.IntegerSet(iValue); }
public int Get() { return _Instance.IntegerGet(); }
}
public MyWrapper(MyClass instance)
{
Integer = new _Integer(instance);
}
}