Obviously using virtual and override is the normal situation, but does this telecoms'ish example count?
public class Pipe
{
// whole bunch of protected member variables such as bandwidth, latency, download limit
// etc,
public int GetCost()
{
// work out cost based on above
}
}
public class BigFatPipe : Pipe
{
public BigFatPipe()
{
// sets up the member variables one way
}
}
public class CheapestPossiblePipe: Pipe
{
public CheapestPossiblePipe()
{
// sets up the member variables another way
}
}
then you might call
PrintPrice(new BigFatPipe())
PrintPrice(new CheapestPossiblePipe())
public void PrintPrice(Pipe pipe)
{
int a = pipe.GetCost();
....
}
You'll get two different answers. This isn't the most useful example but does it count?
This post here has a useful discussion of what exactly polymorphism is.
I think most definitions do not explicitly state that an object must have virtual functions to be polymorphic - so yes, I think your example counts.
Constructor overloading is a recognized method to implement static polymorphism. While this isn't really constructor overloading, it's close. So yes, I'd call it polymorphism.
This pattern does work, but introducing a bunch of classes will confuse the user uselessly: they will wonder what the classes do differently.
A few factories methods will do the same job and will be easier to understand and maintain:
public class Pipe
{
// whole bunch of private member variables such as bandwidth, latency, download limit
// etc,
public int GetCost()
{
// work out cost based on above
}
public static Pipe MakeBigFatPipe()
{
var result = new Pipe();
// sets up the member variables one way
return result;
}
public static Pipe MakeCheapestPossiblePipe()
{
var result = new Pipe();
// sets up the member variables another way
return result;
}
}
If I were you I would use folowing approach:
public interface IGetCost
{
int GetCost();
}
public class Pipe : IGetCost
{
public int GetCost(){}
}
public class BigFatPipe : IGetCost
{
//aggregation
private readonly Pipe _pipe;
public BigFatPipe(Pipe pipe)
{
_pipe = pipe;
}
public int GetCost() { }
}
public class CheapestPossiblePipe : IGetCost
{
private readonly Pipe _pipe;
public CheapestPossiblePipe(Pipe pipe)
{
_pipe = pipe;
}
public int GetCost() { }
}
public static void PrintPrice(IGetCost obj)
{
int cost = obj.GetCost();
Console.WriteLine(cost);
}
static void Main(string[] args)
{
IGetCost p;
p = new Pipe();
PrintPrice(p);
p = new BigFatPipe();
PrintPrice(p);
p = new CheapestPossiblePipe();
PrintPrice(p);
}
I also need to say that there're two different things - polymorphism and overloading
polymorphism
public class foo
{
public virtual void foo1{/*....*/}
}
public class fooA : foo
{
public override void foo1{/*....*/}
}
public class fooB : foo
{
public new void foo1{/*....*/}
}
public class fooC : foo
{
//new is the default modifier
public void foo1{/*....*/}
}
overloading
public class foo{
public int foo1{/*....*/}
public int foo1(int a){/*....*/}
public int foo1(string a){/*....*/}
public int foo1(int a, string b){/*....*/}
}
Related
In C# a static class can not derive from any other class besides object.
Currently I have this base class:
public static class BaseModule
{
public static string UsedSource {get; set;}
public static Write(string text)
{
OtherStaticClass.Log(UsedSource, text);
}
}
Now, depending on which class I'm using, I want to change UsedSource.
// this does not work
internal static class ModuleA : BaseModule
{
static ModuleA(){
UsedSource = "A" // just an example
}
}
// this does not work
internal static class ModuleB : BaseModule
{
static ModuleB(){
UsedSource = "B" // just an example
}
}
Supposed to be called like this
ModuleA.Write("Hi");
ModuleB.Write("Hi");
This approach does not work because a static class cannot derive from anything else than object.
Is there any other way to change the property?
You have a lot of static classes going on here and I'm not entirely sure they're necessary. My example does not use static classes other than for the OtherStaticClass reference you have. I understand this may not be quite what you're looking for; many ways to skin this cat.
public abstract class BaseModule
{
public string UsedSource { get; set; }
public void Write(string text)
{
OtherStaticClass.Log(UsedSource, text);
}
}
public class ModuleA : BaseModule
{
public ModuleA()
{
UsedSource = "A";
}
}
public class ModuleB : BaseModule
{
public ModuleB()
{
UsedSource = "B";
}
}
To get your output then, you just need to create new instances of ModuleA and ModuleB.
var moduleA = new ModuleA();
var moduleB = new ModuleB();
moduleA.Write("Hi");
moduleB.Write("Hi");
Using a static class means using a singleton. Singletons defeat the purpose of tracking the effective dependencies of your classes.
Anyway, you can approach the problem by refactoring your code and using a factory:
In this case, just drop the static keyword and let the class be inheritable (you have to add the appropriate virtual keywords to allow proper inheritance):
public class BaseModule
{
public string UsedSource {get; set;}
public Write(string text)
{
OtherStaticClass.Log(UsedSource, text);
}
}
Then, add an additional class which holds the reference (I gave useless names, focus on the purpose):
public static class MySingleton
{
public static BaseModule _Module;
public static BaseModule Module
{
get
{
return _Module;
}
}
public static void ChangeImplementation (BaseModule module)
{
// do your checks here
_Module = module;
}
}
This way wou can achieve what you ask.
As you can see, this code has several issues, among them it's important to note that this code has global side effects and is not thread safe.
A better approach is to have drop the singleton entirely, and pass the BaseModule class (that can be inherited) as an argument of methods/constructors when needed.
I don't see that you need more than one static class. Instead separate the logic into methods in one static class.
public static class Module
{
private const string SourceA = "A";
private const string SourceB = "B";
public static WriteA(string text)
{
Write(SourceA, text);
}
public static WriteB(string text)
{
Write(SourceB, text);
}
private static Write(string source, string text)
{
OtherStaticClass.Log(source, text);
}
}
Then instead of
ModuleA.Write("Hi");
ModuleB.Write("Hi");
you'd do
Module.WriteA("Hi");
Module.WriteB("Hi");
If you can't change the BaseModule class, you can use it with other state and recover state after using:
public static class BaseModule
{
public static string UsedSource {get; set;}
public static Write(string text)
{
OtherStaticClass.Log(UsedSource, text);
}
}
internal class Writer : IDisposable
{
string _lastSource;
public Writer(string source)
{
_lastSource = BaseModule.UsedSource;
BaseModule.UsedSource = source;
}
public void Dispose()
{
BaseModule.UsedSource = _lastSource;
}
}
internal abstract class Module
{
public abstract Source { get; };
public void Write(string text)
{
using (var writer = new Writer(Source))
{
BaseModule.Write(text);
}
}
}
internal class ModuleA : Module
{
public override Source => "A";
}
internal class ModuleB : Module
{
public override Source => "B";
}
But you must ensure thread safety.
If you can change the BaseModule class:
public static class BaseModule
{
public static Write(string text, string source)
{
OtherStaticClass.Log(source, text);
}
}
internal abstract class Module
{
public abstract Source { get; };
public void Write(string text)
{
BaseModule.Write(text, Source);
}
}
internal class ModuleA : Module
{
public override Source => "A";
}
internal class ModuleB : Module
{
public override Source => "B";
}
I have some device classes like the following sample:
public class MoveSensor() {
public uint GetData() {
// Some logic here
}
}
public class TemperatureSensor {
public double GetData() {
// Some logic here
}
}
public class MultiSensorUnit() {
public MultiSensorData GetData() {
// Some logic here
}
}
public class MultiSensorData {
public int SomeSensor1Data { get; set; }
public byte SomeSensor2Data { get; set; }
public double SomeSensor3Data { get; set; }
}
Yet I have a class to periodically collect a data from these devices:
public class DataCollector() {
public void CollectData() {
// Here I want to collect a data from all devices
}
}
Looks like I should use an interface:
public interface IDataRecievable {
[This is a problem place] GetData();
}
But I can't do it because GetData() returns different types from different devices. I need a design pattern to make usage of devices in DataCollector more universal and generic.
With all of your sensors returning different kinds of data, you may consider move your data processing into each sensor implementation.
If you can do that, here is how I would implement it.
Declare an interface
public interface IDataRecievable<T>
{
T GetData();
void CollectData();
}
And concrete classes:
public class MoveSensor : IDataRecievable<uint>
{
public void CollectData()
{
//do collect logic here
}
public uint GetData()
{
//do get data
}
}
public class TemperatureSensor : IDataRecievable<double>
{
public void CollectData()
{
//do collect logic here
}
public double GetData()
{
//do get data
}
}
And data collector class
public class DataCollector
{
public void CollectData()
{
var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(type => type.GetInterfaces().Any(x => x.IsGenericType
&& x.GetGenericTypeDefinition() == typeof(IDataRecievable<>)));
foreach (var type in typesToRegister)
{
dynamic sensor = Activator.CreateInstance(type);
sensor.CollectData();
}
}
}
I get all classes implement IDataRecievable<>, create an instance and call the CollectData() method. You can always call GetData() isstead of CollectData() if you want.
You could encapsulate the functionality of the returned data into various implementations of the same interface. For example, if the data will be displayed, each sensor returns a different type that displays the data in a different way. For example:
public interface Sensor {
Data GetData();
}
public interface Data {
void Display();
}
public class IntData : Data {
public void Display() { ... }
}
public class DoubleData : Data {
public void Display() { ... }
}
public class MoveSensor : Sensor {
public IntData GetData() {
// ... return IntData ...
}
}
public class TemperatureSensor : Sensor {
public DoubleData GetData() {
// ... return DoubleData ...
}
}
Then some client can iterate through each sensor and display the data:
List<Sensor> sensors = // ...
foreach (Sensor sensor in sensors) {
sensor.Display();
}
This is not restricted to displaying the data, the Data interface can incorporate any type of functionality. For example, if the data needed to be stored into a database, you can pass some proxy to the database to a method and each Data implementation would know how to store itself in the database:
public class DatabaseProxy {
public void StoreInt(int value) { ... }
public void StoreDouble(double value) { ... }
}
public interface Data {
void StoreData(DatabaseProxy proxy);
}
public class IntData : Data {
private int _value;
public IntData(int value) {
_value = value;
}
public void StoreData(DatabaseProxy proxy) {
proxy.StoreInt(_value);
}
}
public class DoubleData : Data {
private double _value;
public DoubleData(double value) {
_value = value;
}
public void StoreData(DatabaseProxy proxy) {
proxy.StoreDouble(_value);
}
}
The idea is to shift the responsibility of using the returned data away from some external entity and hand it to the data itself. Ergo, the Data implementation is closest to the data it is storing and thus, it should be responsible for handling it. If there are too many things that need to be accomplished by Data, then more complex techniques can be used, like handlers or callbacks to separate the data from the handling of data.
It depends on what the results of each sensor are going to be. You have given examples of a uint and a double. I guess other sensors could in theory return strings or even complex compound objects.
The answer from a sensor is meaningless without knowledge of what that sensor measures, and that would obviously be known to the consumer of this data. Is your problem in the intermediate storage in DataCollector?
I can imagine Dictionary where you would want to hold an arbitrary number of sensors and their results. Can you live with the boxing/unboxing performance overheads? If there isn't a massive number of sensors then this should be negligible. If so, you can do something like:
using System;
using System.Collections.Generic;
using System.Linq;
public interface IDataRecievable
{
object GetData();
}
public class PiSensor : IDataRecievable
{
public object GetData() {
return (object)3.14m;
}
}
public class StringSensor : IDataRecievable
{
public object GetData() {
return (object)"Hello World";
}
}
public class DataCollector
{
private List<IDataRecievable> sensors;
private Dictionary<Type, object> sensorResults = new Dictionary<Type, object>();
public DataCollector(IEnumerable<IDataRecievable> sensorsToPoll)
{
this.sensors = sensorsToPoll.ToList();
}
public T GetResultFromSensor<T>(Type sensorType)
{
return (T)this.sensorResults[sensorType];
}
public void CollectData()
{
foreach (IDataRecievable sensor in this.sensors)
{
sensorResults[sensor.GetType()] = sensor.GetData();
}
}
}
public class Program
{
public static void Main()
{
List<IDataRecievable> sensors = new List<IDataRecievable>
{
new PiSensor(),
new StringSensor()
};
DataCollector dc = new DataCollector(sensors);
dc.CollectData();
decimal pi = dc.GetResultFromSensor<decimal>(typeof(PiSensor));
string greeting = dc.GetResultFromSensor<string>(typeof(StringSensor));
Console.WriteLine(2 * pi);
Console.WriteLine(greeting);
}
}
I would also probably go with Trung Le's implementation, but I would also have some interface for giving the result of the collecion:
public interface ICollectResultReceiver
{
void ReceiveCollectResult(
// whatever you are storing
object someData
);
}
I would also use another interface for the collection process, because it feels like data collection isn't a part of getting data:
public interface IDataRecievable<T>
{
T GetData();
}
public interface IDataCollectable
{
void CollectData(ICollectDataResultReceiver resultReceiver);
}
This way the user of IDataCollectable classes don't need to care about the types, and just use a for loop to run all the collection.
public interface IDataCollector
{
void Add(IDataCollectable collectable);
void CollectData();
}
public class DataCollector : IDataCollector
{
private readonly ICollectDataResultReceiver _resultReceiver;
private readonly List<IDataCollectable> _collectables = new List<IDataCollectable>();
public DataCollector(ICollectDataResultReceiver resultReceiver)
{
_resultReceiver = resultReceiver;
}
public void Add(IDataCollectable collectable)
{
_collectables.Add(collectable);
}
public void CollectData()
{
foreach(var collectable in _collectables)
{
collectable.CollectData(_resultReceiver);
}
}
}
Other than that, I would also make interfaces for each sensor, because there are times where knowing what kind of module you're using is necessary.
public interface IMoveSensorDataReceivable : IDataReceivable<uint> { }
public interface ITemperatureSensorDataReceivable : IDataReceivable<double> { }
public interface IMultiSensorDataReceivable : IDataReceivable<MultiSensorData> { }
So MultiSensorData would be more visible of what kind of data it has.
public class MultiSensorData
{
public uint GetSensorData1() => _moveSensor.GetData();
public double GetSensorData2() => _temperatureSensor.GetData();
private readonly IMoveSensorDataReceivable _moveSensor;
private readonly ITemperatureSensorDataReceivable _temperatureSensor;
public MultiSensorData(
IMoveSensorDataReceivable moveSensor,
ITemperatureSensorDataReceivable temperatureSensor)
{
_moveSensor = moveSensor;
_temperatureSensor = temperatureSensor;
}
}
It is also important to use interfaces instead of concrete classes for better testing. Even though MultiSensorData doesn't need much testing, your tests would be like so:
public class TestClass
{
[Fact]
public void MultiSensorDataTest()
{
var dummyTempSensor = new DummyTempSensor();
var dummyMoveSensor = new DummyMoveSensor();
var multiSensorData = new MultiSensorData(dummyMoveSensor, dummyTempSensor);
Assert.Equal(10, multiSensorData.GetSensorData1());
Assert.Equal(0.5, multiSensorData.GetSensorData2());
}
private class DummyTempSensor : ITemperatureSensorDataReceivable
{
public double GetData() => 0.5;
}
private class DummyMoveSensor : IMoveSensorDataReceivable
{
public uint GetData() => 10;
}
}
I'm not that new to C# but don't have as much experience as in Java.
As you know, in Java, we can access all the private members from outer classes.
So I tried the same thing in C# because I had some fields and methods needed to be accessed from only inside my plugin library and didn't want it to be shown to users. A simple example can be like this.
public static class StaticClass {
public class InstanceClass {
private int oldValue;
public int Value;
}
public static void Backup(InstanceClass ic) {
ic.oldValue = ic.Value;
}
public static void Restore(InstanceClass ic) {
ic.Value = ic.oldValue;
}
}
If I make the field oldValue public, then it'll be mess and look dirty when end users use the plugin. It doesn't have to be an Inner class or in a some specific form. I just want to know if there is any way to control or access private members of an instance from other static classes in the same assembly only by me.
For allowing access only within assembly use internal modifier.
public class InstanceClass {
internal int oldValue;
public int Value;
}
This is not possible in C#. The container class has no special access over the nested class.
You can access private members of the container from the nested class, but not vice versa. The pattern you're trying to use simply isn't used in C# - it's a violation of member accessibility. There are some hacks to force the Java pattern on C# (using reflection or abusing interfaces), but they are just that - hacks.
The "cleanest" approach might look something like this:
public static class StaticClass
{
private interface IInstanceClassInternal
{
int OldValue { get; set; }
}
public sealed class InstanceClass : IInstanceClassInternal
{
int IInstanceClassInternal.OldValue { get; set; }
public int Value;
}
public static void Backup(InstanceClass ic)
{
((IInstanceClassInternal)ic).OldValue = ic.Value;
}
public static void Restore(InstanceClass ic)
{
ic.Value = ((IInstanceClassInternal)ic).OldValue;
}
}
It's obvious that you're trying to write Java in C# - the patterns, the coding style... That's probably a bad idea. Those static methods should probably be extension methods. The "hidden functionality in an object" doesn't quite sit with C#'s notion of OOP - your parent shouldn't have free access to your guts, it should only really have the same public interface everyone else has. After all, that's the whole point of LSP - such tight coupling is quite tricky for any extensibility. Why separate StaticClass from InstanceClass in the first place, if you want StaticClass to mess with InstanceClasses privates? Just make Backup and Restore public members of InstanceClass - or even a part of an interface (perhaps even through explicit implementation, if you want to "hide" it from users of InstanceClass).
You can use the internal access modifier, see https://msdn.microsoft.com/en-us/library/ms173121.aspx
Internal is only visible from inside the assembly
Example: https://dotnetfiddle.net/FNavfE
Have you tried to make it "internal"? It will be available in same dll but not external dll.
public class InstanceClass {
internal int oldValue;
public int Value;
}
Technically, you can use Reflection (if you insist on private field and a static class methods):
using System.Reflection;
...
public static void Backup(InstanceClass ic) {
if (null == ic)
throw new ArgumentNullException("ic");
ic.GetType()
.GetField("oldValue", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(ic, ic.Value);
}
public static void Restore(InstanceClass ic) {
if (null == ic)
throw new ArgumentNullException("ic");
ic.Value = (int) (ic.GetType()
.GetField("oldValue", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(ic));
}
however, a much better approach is to change access modifier from private to internal:
public class InstanceClass {
internal int oldValue;
public int Value;
}
Even better solution is to move both Backup and Restore methods into InstanceClass:
public class InstanceClass {
private int oldValue;
public int Value;
public void Backup() {
oldValue = Value;
}
public void Restore() {
Value = oldValue;
}
}
This field oldValue is an implementation detail of both StaticClass and InstanceClass. Lets make InstanceClass an implementation detail of StaticClass and export an interface StaticClass.IInstance to external clients:
public static class StaticClass {
public interface IInstance {
int Value { get; set; }
}
private class InstanceClass: IInstance {
public int oldValue;
public Value { get; set; }
}
// Static class becomes responsible for handing out `IInstance` objects
public static IInstance GetInstance() {
return new InstanceClass();
}
public static void Backup(IInstance i) {
if (i is InstanceClass ic) {
ic.oldValue = ic.Value;
}
else {
throw new InvallidOperationException("Can only Backup IInstance objects that were created by GetInstance");
}
}
public static void Restore(IInstance i) {
if (I is InstanceClass ic)
{
ic.Value = ic.oldValue;
}
else {
throw new InvallidOperationException("Can only Restore IInstance objects that were created by GetInstance");
}
}
This solution is similar to the one Luaan proposes. But instead of using an interface to export private data, it uses an interface to limit the publicly available data; to my opinion this is a cleaner design with less surprises.
It does change Value from a field to a property; so when you really need a field, this pattern does not work.
The static class in the example of OP makes it a bit awkward and having better solutions, but imagine this in a regular class, perhaps in a repository. Working on a repository, where observers should be notified when properties of items in the repository are set and not wanting the items to contain a reference to the repository or to the repositories observers, led me to searching for "method only accessible to container class?" which led me to this question.
I intend to solve it as follows:
public class Repo
{
public interface IItem
{
int Id { get; }
string MyProperty { get; }
}
private class Item
{
public int Id { get; }
public string MyProperty { get; private set; }
public bool TrySetMyProperty(string newValue)
{
if (!Equals(MyProperty, newValue) &&
IsPreconditionValid())
{
MyProperty = newValue;
return true;
}
else
{
return false;
}
IsPreconditionValid() => true;
}
}
public event EventHandler<EventArgs> OnChanged;
private readonly ConcurrentDictionary<int, Item> items = new ConcurrentDictionary<int, Item>();
public IItem GetOrCreateItemById(int id)
{
bool changed = false;
IItem result = items.GetOrAdd(int, CreateItem);
if (changed)
{
OnChanged?.Invoke(this, EventArgs.Empty);
}
return result;
IItem CreateItem(int key)
{
changed = true;
return new Item() { Id = key };
}
}
public bool TrySetItemMyProperty(int id, string newValue)
{
if (items.TryGet(id, out Item i))
{
if (i.TrySetMyProperty(newValue))
{
OnChanged?.Invoke(this, EventArgs.Empty);
return true;
}
}
return false;
}
}
I have a static Class and within it I have multiple public static attributes. I treat this class as my global class.
However now I need to treat this class as a variable so that I can pass it to a method of another class for processing..
I can't instantiate this class.. So in effect I can only assign the variables inside this class.
Is my understanding correct or am I missing something?
public static class Global
{
public const int RobotMax = 2;
// GUI sync context
public static MainForm mainForm;
public static SynchronizationContext UIContext;
// Database
public static Database DB = null;
public static string localDBName = "local.db";
public static Database localDB = null;
public static Database ChangeLogDB = null;
public static string changeLogDBName = "ChangeLog.db";
}
Let say I have a class like this, and I need to somehow keep a copy of this in another class maybe
public static class Global_bk
{
public const int RobotMax = 2;
// GUI sync context
public static MainForm mainForm;
public static SynchronizationContext UIContext;
// Database
public static Database DB = null;
public static string localDBName = "local.db";
public static Database localDB = null;
public static Database ChangeLogDB = null;
public static string changeLogDBName = "ChangeLog.db";
}
I need to copy the contents from Global to Global_bk.
And after that I need to compare the contents of the two classes in a method like
static class extentions
{
public static List<Variance> DetailedCompare<T>(T val1, T val2)
{
List<Variance> variances = new List<Variance>();
FieldInfo[] fi = val1.GetType().GetFields();
foreach (FieldInfo f in fi)
{
Variance v = new Variance();
v.Prop = f.Name;
v.valA = f.GetValue(val1);
v.valB = f.GetValue(val2);
if (!v.valA.Equals(v.valB))
variances.Add(v);
}
return variances;
}
}
class Variance
{
string _prop;
public string Prop
{
get { return _prop; }
set { _prop = value; }
}
object _valA;
public object valA
{
get { return _valA; }
set { _valA = value; }
}
object _valB;
public object valB
{
get { return _valB; }
set { _valB = value; }
}
}
So on my main form, how do I go about calling the compare method and passing the static Global class inside?
example: extentions.DetailedCompare(Global, Global_bk) ? Of course this would give me an error because I cant pass a type as a variable.
Please help me, this is driving me nuts...
How about the singleton pattern ? You can pass reference to shared interface (IDoable in exable below) and still have just one instance.
I.E.:
public interface IDoable {
int Value { get; set; }
void Foo();
}
public static class DoableWrapper {
private MyDoable : IDoable {
public int Value { get;set; }
public void Foo() {
}
}
private static IDoable s_Doable = new MyDoable();
public static IDoable Instance {
get { return s_Doable; }
}
}
Singleton is the way to go here. You can do it like this:
internal class SomeClass
{
private static SomeClass singleton;
private SomeClass(){} //yes: private constructor
public static SomeClass GetInstance()
{
return singleton ?? new SomeClass();
}
public int SomeProperty {get;set;}
public void SomeMethod()
{
//do something
}
}
The GetInstance Method will return you a SomeClass object that you can edit and pass into whatever you need.
You can access the members with classname.membername.
internal static class SomeClass
{
public static int SomeProperty {get;set;}
public static void SomeMethod()
{
//do something
}
}
static void main()
{
SomeClass.SomeProperty = 15;
SomeClass.SomeMethod();
}
The only way you are going to obtain a variable with the "class" information is using reflection. You can get a Type object for the class.
namespace Foo {
public class Bar
{
}
}
Type type = Type.GetType("Foo.Bar");
Otherwise, if you are really describing a class "instance" then use an object and simply instantiate one.
C# offers no other notation for class variables.
Without any code in the subclasses, I'd like an abstract class to have a different copy of a static variable for each subclass. In C#
abstract class ClassA
{
static string theValue;
// just to demonstrate
public string GetValue()
{
return theValue;
}
...
}
class ClassB : ClassA { }
class ClassC : ClassA { }
and (for example):
(new ClassB()).GetValue(); // returns "Banana"
(new ClassC()).GetValue(); // returns "Coconut"
My current solution is this:
abstract class ClassA
{
static Dictionary<Type, string> theValue;
public string GetValue()
{
return theValue[this.GetType()];
}
...
}
While this works fine, I'm wondering if there's a more elegant or built-in way of doing this?
This is similar to Can I have different copies of a static variable for each different type of inheriting class, but I have no control over the subclasses
There is a more elegant way. You can exploit the fact that statics in a generic base class are different for each derived class of a different type
public abstract class BaseClass<T> where T : class
{
public static int x = 6;
public int MyProperty { get => x; set => x = value; }
}
For each child class, the static int x will be unique for each unique T
Lets derive two child classes, and we use the name of the child class as the generic T in the base class.
public class ChildA: BaseClass<ChildA>
{
}
public class ChildB : BaseClass<ChildB>
{
}
Now the static MyProperty is unique for both ChildA and ChildB
var TA = new ChildA();
TA.MyProperty = 8;
var TB = new ChildB();
TB.MyProperty = 4;
While this works fine, I'm wondering if there's a more elegant or built-in way of doing this?
There isn't really a built-in way of doing this, as you're kind of violating basic OO principles here. Your base class should have no knowledge of subclasses in traditional object oriented theory.
That being said, if you must do this, your implementation is probably about as good as you're going to get, unless you can add some other info to the subclasses directly. If you need to control this, and you can't change subclasses, this will probably be your best approach.
This is a little different than what you're asking for, but perhaps accomplishes the same thing.
class Program
{
static void Main(string[] args)
{
Console.WriteLine((new B()).theValue);
Console.WriteLine((new C()).theValue);
Console.ReadKey();
}
}
public abstract class A
{
public readonly string theValue;
protected A(string s)
{
theValue = s;
}
}
public class B : A
{
public B(): base("Banana")
{
}
}
public class C : A
{
public C(): base("Coconut")
{
}
}
There's an alternative solution which might or might not be better than yours, depending on the use case:
abstract class ClassA
{
private static class InternalClass<T> {
public static string Value;
}
public string GetValue()
{
return (string)typeof(InternalClass<>)
.MakeGenericType(GetType())
.GetField("Value", BindingFlags.Public | BindingFlags.Static)
.GetValue(null);
}
}
This approach is used in EqualityComparer<T>.Default. Of course, it's not used for this problem. You should really consider making GetValue abstract and override it in each derived class.
What about this?
class Base {
protected static SomeObjectType myVariable;
protected void doSomething()
{
Console.WriteLine( myVariable.SomeProperty );
}
}
class AAA : Base
{
static AAA()
{
myVariable = new SomeObjectType();
myVariable.SomeProperty = "A";
}
}
class BBB : Base
{
static BBB()
{
myVariable = new SomeObjectType();
myVariable.SomeProperty = "B";
}
}
It works for me.
Would be even nicer with Interface.
Simple solution: just use word "new".
public abstract class AbstractClass
{
public static int Variable;
}
public class RealizationA : AbstractClass
{
public new static int Variable;
}
public class RealizationB : AbstractClass
{
public new static int Variable;
}
And the result:
AbstractClass.Variable = 1;
RealizationA.Variable = 2;
RealizationB.Variable = 3;
Console.WriteLine(AbstractClass.Variable); //1
Console.WriteLine(RealizationA.Variable); //2
Console.WriteLine(RealizationB.Variable); //3
or you can use property:
//in abstract class
public static int Variable {get; set;}
//in child class
public static new int Variable {get; set;}
or function (but remember to add "new" to both variable and function):
//in abstract class
protected static int Variable;
public static int GetVariable() { return Variable; }
public static void SetVariable(int v) { Variable = v; }
//in child class
protected new static int Variable;
public static new int GetVariable() { return Variable; }
public static new void SetVariable(int v) { Variable = v; }
or you can use private variables (you don't need to use "new") with functions to get and set:
//in abstract class
private static int Variable;
//get and set methods
//in child class
private static int Variable;
//get and set methods