Related
How do I store objects in a list, but have them retain their original type? Without being casted to their common superclass.
So that the below code can work:
using System;
using System.Collections.Generic;
public class Test
{
public static void Main(string[] args)
{
var list = new List<Super>()
{
new Type1 { Number = 1, Info = "infomatin" },
new Type2 { Number = 2, Prop = "propty" }
};
foreach (var t in list)
{
Doer.Do(t);
}
}
}
public class Super
{
public int Number { get; set; }
}
public class Type1 : Super
{
public string Info { get; set; }
}
public class Type2 : Super
{
public string Prop { get; set; }
}
public static class Doer
{
public static void Do(Type1 arg)
{
Console.WriteLine($"Got type 1 with {arg.Info}");
}
public static void Do(Type2 arg)
{
Console.WriteLine($"Got type 2 with {arg.Prop}");
}
}
Wanted output:
Got type 1 with infomatin
Got type 2 with propty
Actual output, compiler error:
Test.cs(15,21): error CS1503: Argument 1: cannot convert from 'Super' to 'Type1'
I could do this inside the foreach
if (t instanceof Type1)
Doer.Do((Type1) t);
else if (t instanceof Type2)
Doer.Do((Type2) t);
But I don't want to have to write so much code. Especially as I add more subclasses of Super.
I would like to have to add only an additional method to my Doer to handle the new type, then the rest is taken care of.
You can use pattern matching, with only one Do() method
public static void Do(Super arg)
{
switch(arg)
{
case Type1 t1:
Console.WriteLine($"Got type 1 with {t1.Info}");
break;
case Type2 t2:
Console.WriteLine($"Got type 2 with {t2.Prop}");
break;
default:
throw new NotSupportedException();
}
}
As far as avoiding casting, I feel you have misunderstood how C# works. When you store in a base class, the memory contents are still the of the derived class and there is not casting in the sense of copying data from one type to another
This type of operation does not involve any data copy
Super obj = new Type1();
Neither does this
Type1 t1 = (Type1)obj;
It just the reference t1 putting on a different "mask" than obj, and the data behind the mask is the same.
Edit 1
A any casting (of the form (type)value in C#) is cast that might include a conversion or not. Some examples where obj is if type object, sup is of type class Super, t1 is of type class Type1 : Super and t2 is of type class Type2 : Super.
No conversion, or identity casts
obj = sup;
sup = t1;
sup = t2;
sup = t1; t1 = (Type1)sup;
obj = t1; sup = (Super)obj;
obj = t1; sup = (Type1)t1;
The code below requires the following custom conversion code to be added to Type1 and Type2 respectively.
public static implicit operator Type1(Type2 t2) => new Type1() { Info = t2.Prop };
public static explicit operator Type2(Type1 t1) => t1.Info.StartsWith("prop") ? new Type2() { Prop = t1.Info } : throw new NotSupportedExpection();
Implicit Conversion casts (data copy, may fail)
{ // Implicit conversion Type2 -> Type1
object obj = new Type2() { ID = 2, Prop = "propval" };
Type1 t1 = (Type2)obj;
}
Explicit Conversion casts (data copy, may fail)
{
// Explicit conversion Type1 -> Type2
object obj = new Type1() { ID = 1, Info = "propInfo" };
Type2 t2 = (Type2)(Type1)obj;
}
Read https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/conversions. for more accurate information.
If you find yourself using switch/case and casting, there's a good chance you're doing it wrong. With a properly designed object model, it shouldn't be necessary.
For example
abstract public class Super
{
public int Number { get; set; }
public abstract void Do();
}
public class Type1 : Super
{
public string Info { get; set; }
public override void Do()
{
Console.WriteLine($"Got type 1 with {this.Info}");
}
}
public class Type2 : Super
{
public string Prop { get; set; }
public override void Do()
{
Console.WriteLine($"Got type 2 with {this.Prop}");
}
}
Now you can just do this in your loop:
public static void Main(string[] args)
{
var list = new List<Super>()
{
new Type1 { Number = 1, Info = "infomatin" },
new Type2 { Number = 2, Prop = "propty" }
};
foreach (var t in list)
{
t.Do();
}
}
The above is consistent with Tell, Don't Ask which is a traditional object-oriented philosophy.
If you are worried about separation of concerns (for example, you don't want your classes to have knowledge of "Console") then you can inject the external functionality:
abstract public class Super
{
public int Number { get; set; }
public abstract void Do(Action<int> action);
}
public class Type1 : Super
{
public string Info { get; set; }
public override void Do(Action<int> action)
{
action(this.Info);
}
}
public class Type2 : Super
{
public string Prop { get; set; }
public override void Do(Action<int> action)
{
action(this.Prop);
}
}
public static void Main(string[] args)
{
var list = new List<Super>()
{
new Type1 { Number = 1, Info = "infomatin" },
new Type2 { Number = 2, Prop = "propty" }
};
foreach (var t in list)
{
t.Do( x => Console.WriteLine("The value that we're interested in is {0}", x));
}
}
There is one more situation which may apply here (based on your comments). Let's say you have "clean" DTO objects that have no methods, and you don't want to add any for whatever reason, e.g. maybe the DTOs are code-generated and you can't modify them. This is actually a common situation (I like methodless DTOs too).
To make the situation more real, let's use more meaningful examples. Let's say you have a variety of objects that might contain an end user's name, but with various different identifiers:
abstract public class Super
{
}
public class Type1 : Super
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Type2 : Super
{
public string FullName { get; set; }
}
The temptation here is to write a switch case like this:
foreach (var t in list)
{
switch (t)
{
case Type1 type1 : Console.WriteLine("Name is {0} {1}", type1.FirstName, type1.LastName);
case Type2 type2: Console.WriteLine("Name is {0}", type2.FullName);
default:
throw new InvalidOperationException();
}
}
The problem here is that runtime throw, which will occur any time someone adds a different object type but doesn't remember to update your switch statement. This might not be a problem, but it also might be a huge problem, e.g. if your DTOs are held in a separate library from your Do processor and you would rather not have to update both at the same time (which could be a deployment concern under certain architectures).
What is missing here is a business concept of "Name" agnostic of where it came from. Somewhere, some code has to translate these various objects into something that has a name, and preferably that logic would be encapsulated somewhere.
That's where I would use an adapter class.
class NameHolder
{
public string FullName { get; }
public NameHolder(Type1 type1)
{
this.FullName = type1.FirstName + " " + type1.LastName;
}
public NameHolder(Type2 type2)
{
this.FullName = type2.FullName;
}
}
With the addition of this missing business concept, the logic become very simple:
public static void Main(string[] args)
{
var list = new List<NameHolder>()
{
new NameHolder(new Type1 { Number = 1, Info = "infomatin" }),
new NameHolder(new Type2 { Number = 2, Prop = "propty" })
};
foreach (var t in list)
{
Do(t.FullName);
}
}
Notice the lack of throw. The advantage of this approach is that all types are resolved at compile time, so if you forget to add logic to map the proper fields, you will get a compile time error, which you can detect and fix immediately.
Suppose I have a class A:
class A
{
void b() {...}
}
and a class B:
class B
{
A m;
}
This way, if I write B x, I can call x.m.b().
What I need is to dynamically create a method b() inside the B class, so I could use it as x.b() (of course, the results from calls x.m.b() and x.b() should be the same).
How can I do it?
There is one generic solution (where you won't have to f.e create delegates for every method from A you want). Unfortunately, It won't be a strongly-typed one. If you want so, please see other answers.
class A
{
public int B()
{
return 1;
}
}
class B : DynamicObject
{
private readonly A m = new A();
private static readonly Lazy<IEnumerable<MethodInfo>> AMethods =
new Lazy<IEnumerable<MethodInfo>>(() =>
{
var type = typeof (A);
return type.GetMethods(
BindingFlags.Instance |
BindingFlags.Public);
});
public override bool TryInvokeMember(
InvokeMemberBinder binder,
object[] args,
out object result)
{
if (base.TryInvokeMember(binder, args, out result))
{
return true;
}
var methods = AMethods.Value;
var method = methods.SingleOrDefault(mth => mth.Name == binder.Name);
// TODO: additional match (arguments type to handle overloads)
if (method == null)
{
result = null;
return false;
}
result = method.Invoke(this.m, args);
return true;
}
public int OtherBMethods()
{
return 2;
}
}
Usage:
var b = new B();
int result = ((dynamic)b).B();
int other = b.OtherBMethods();
or
dynamic b = new B();
int result = b.B();
int other = b.OtherBMethods();
You could do this with delegates, in modern C# this could look like this
public class A
{
public void b() {...}
}
public class B
{
private A m = new A();
public Action b = ()=>m.b();
}
public void Main()
{
new B().b(); // This now invokes your delegates that invokes the b method on it's internal m object
}
Could also just do it with classical methods and simply expose a b method that does the exact same thing, don't see anything special / hard here? If you're trying to accomplish something else you need to clarify your question, like if you want to automate this there are easy compile time (T4 text templates) or at runtime (generating dynamic proxies).
What you are going to do is implement Decorator pattern in C#.
GoF defines Decorator pattern as "Attach additional responsibilities
to an object dynamically. Decorators provide a flexible alternative to
subclassing for extending functionality.
I would like to recommend look throught this article "Understanding and Implementing Decorator Pattern in C#".
I have created a simple example of the Decorator pattern implementation when you decorate Concrete with A and B functionality.
interface IDecorator
{
void Print();
}
class Concrete : IDecorator
{
public void Print()
{
Console.WriteLine("-> Concrete");
}
}
class A : IDecorator
{
IDecorator decorator;
public A(IDecorator decorator)
{
this.decorator = decorator;
}
public void Print()
{
decorator.Print();
Console.WriteLine("-> A");
}
}
class B : IDecorator
{
IDecorator decorator;
public B(IDecorator decorator)
{
this.decorator = decorator;
}
public void Print()
{
decorator.Print();
Console.WriteLine("-> B");
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("concrete object that should be decorated");
var concrete = new Concrete();
concrete.Print();
Console.WriteLine("let's decorate this object with A decorator");
var decoratedWithA = new A(concrete);
decoratedWithA.Print();
Console.WriteLine("let's decorate this object with B decorator");
var decoratedWithB = new B(concrete);
decoratedWithB.Print();
Console.WriteLine("let's decorate concrete with A and B");
var decoratedWithAB = new B(new A(concrete));
decoratedWithAB.Print();
}
}
I have an abstract A class and classes A1 : A, A2 : A, A3 : A. Then i
also have a method named c(). I want to create classes
A1_with_c_method, A2_with_c_method, A3_with_c_methos while leaving A1,
A2 and A3 unharmed. What is the best way to do this? – h8red
You could do something like this:
abstract class A
{
}
class A1 : A
{
}
class A2 : A
{
}
class A3 : A
{
}
#region Not a good idea, because too many classes
class A1_with_c : A1
{
public void c() { }
}
class A2_with_c : A2
{
public void c() { }
}
class A3_with_c : A3
{
public void c() { }
}
#endregion
// Decorate A with the c() method
class BaseDecorator
{
public A Instance { get; private set; }
public BaseDecorator(A instance)
{
Instance = instance;
}
public virtual void c()
{
// do something with instance
}
}
class Decorator : BaseDecorator
{
BaseDecorator decorator;
public Decorator(BaseDecorator decorator)
: base(decorator.Instance)
{
this.decorator = decorator;
}
public override void c()
{
Console.WriteLine("Ok");
}
}
class Program
{
static void Main(string[] args)
{
// not good
new A1_with_c().c();
new A2_with_c().c();
new A3_with_c().c();
// better
var a_with_c = new BaseDecorator(new A1());
a_with_c.c();
// Let's decorate with something interesting
new Decorator(a_with_c).c();
}
}
I agree with the comments that this really seems odd and I'm wondering why you would ever want to do this but here is a possibility for you.
interface IHasMethodb
{
void b();
}
class A : IHasMethodb
{
public void b() { ... }
}
class B : IHasMethodb
{
A m;
public void b() { return m.b(); }
}
Is this what you're trying to do?
It seems like you either want the concept of wrapping a method, which in your example is as simple as:
class A {
public void b() { ... }
}
class B {
A m;
public void b() { m.b(); }
}
Allowing you to:
B x = new B();
x.b();
If you want to be able to "dynamically create" the method then this might be more applicable, using an Action<T> to allow you to do whatever you like with the A instance, without actually exposing it:
class A {
public void b() {...}
}
class B {
A m;
public Action<A> doSomethingWithA;
public void b() {
if (doSomethingWithA != null)
doSomethingWithA(m);
}
}
Then you can:
B x = new B();
x.doSomethingWithA = a => a.b();
x.b();
I have say 3 classes, Animal, Cat & Dog.
// calling code
var x = new Animal("Rex"); // would like this to return a dog type
var x = new Animal("Mittens"); // would like this to return a cat type
if(x.GetType() == typeof(Dog))
{
x.Bark();
}
else
{
x.Meow();
}
class Animal
{
public Animal(string name)
{
// check against some list of dog names ... find rex
// return Animal of type Dog.
// if not...
// check against some list of cat names ... find mittens
// return Animal of type Cat.
}
}
Is this possible somehow? If not is there something similar I can do?
What you are looking for is either a 'virtual constructor' (not possibe in C#) or the Factory pattern.
class Animal
{
// Factory method
public static Animal Create(string name)
{
Animal animal = null;
... // some logic based on 'name'
animal = new Zebra();
return animal;
}
}
The Factory method can also be placed in another (Factory) class. That gives better decoupling etc.
No. Basically the right fix is to use a static method which can create an instance of the right type:
var x = Animal.ForName("Rex");
var x = Animal.ForName("Mittens");
...
public abstract class Animal
{
public static Animal ForName(string name)
{
if (dogNames.Contains(name))
{
return new Dog(name);
}
else
{
return new Cat(name);
}
}
}
Or this could be an instance method in an AnimalFactory type (or whatever). That would be a more extensible approach - the factory could implement an interface, for example, and could be injected into the class which needed to create the instances. It really depends on the context though - sometimes that approach is overkill.
Basically, a new Foo(...) call always creates an instance of exactly Foo. Whereas a static method declared with a return type of Foo can return a reference to any type which is compatible with Foo.
No I dont think it is possible in the way that you want.
You could create a static class that has a method that returns an animal based on a name e.g.
static Animal CreateAnimal(string name)
{
if(catList.Contains(name))
return new Cat(name");
else if(dogList.Contains(name))
return new Dog(name);
return null;
}
The other answers show that you need to use a factory pattern but I wanted to give you a more "practical" example of how you would do it. I did exactly what you where doing, however I was working with the EPL2 printer language. When I saw X I needed to create a instance of class Rectangle, when I saw A I needed to create a instance of class Text.
(I wrote this a long time ago so I am sure some of the things I did could be improved upon).
public partial class Epl2CommandFactory
{
#region Singelton pattern
private static volatile Epl2CommandFactory m_instance;
private static object m_syncRoot = new object();
public static Epl2CommandFactory Instance
{
get
{
if (m_instance == null)
{
lock (m_syncRoot)
{
if (m_instance == null)
{
m_instance = new Epl2CommandFactory();
}
}
}
return m_instance;
}
}
#endregion
#region Constructor
private Epl2CommandFactory()
{
m_generalCommands = new Dictionary<string, Type>();
Initialize();
}
#endregion
#region Variables
private Dictionary<string, Type> m_generalCommands;
private Assembly m_asm;
#endregion
#region Helpers
private void Initialize()
{
Assembly asm = Assembly.GetAssembly(GetType());
Type[] allTypes = asm.GetTypes();
foreach (Type type in allTypes)
{
// Only scan classes that are not abstract
if (type.IsClass && !type.IsAbstract)
{
// If a class implements the IEpl2FactoryProduct interface,
// which allows retrieval of the product class key...
Type iEpl2FactoryProduct = type.GetInterface("IEpl2GeneralFactoryProduct");
if (iEpl2FactoryProduct != null)
{
// Create a temporary instance of that class...
object inst = asm.CreateInstance(type.FullName);
if (inst != null)
{
// And generate the product classes key
IEpl2GeneralFactoryProduct keyDesc = (IEpl2GeneralFactoryProduct)inst;
string key = keyDesc.GetFactoryKey();
m_generalCommands.Add(key, type);
inst = null;
}
}
}
}
m_asm = asm;
}
#endregion
#region Methods
public IEpl2Command CreateEpl2Command(string command)
{
if (command == null)
throw new NullReferenceException("Invalid command supplied, must be " +
"non-null.");
Type type;
if (!m_generalCommands.TryGetValue(command.Substring(0, 2), out type))
m_generalCommands.TryGetValue(command.Substring(0, 1), out type);
if (type != default(Type))
{
object inst = m_asm.CreateInstance(type.FullName, true,
BindingFlags.CreateInstance,
null, null, null, null);
if (inst == null)
throw new NullReferenceException("Null product instance. " +
"Unable to create necessary product class.");
IEpl2Command prod = (IEpl2Command)inst;
prod.CommandString = command;
return prod;
}
else
{
return null;
}
}
#endregion
}
The way the code works is I use the singleton pattern to create a factory class so people can call var command = Epl2CommandFactory.Instance.CreateEpl2Command("..."); passing in the EPL2 command string and it returns a instance of the class that represents that specific class.
During initialization I use reflection to find classes that support the IEpl2GeneralFactoryProduct interface, if the class supports the interface the factory stores the one or two letter code representing the printer command in a dictionary of types.
When you try to create the command the factory looks up the printer command in the dictionary and creates the correct class, it then passes the full command string on to that class for further processing.
Here is a copy of a command class and it's parents if you wanted to see it
Rectangle:
[XmlInclude(typeof(Rectangle))]
public abstract partial class Epl2CommandBase { }
/// <summary>
/// Use this command to draw a box shape.
/// </summary>
public class Rectangle : DrawableItemBase, IEpl2GeneralFactoryProduct
{
#region Constructors
public Rectangle() : base() { }
public Rectangle(Point startingLocation, int horozontalEndPosition, int verticalEndPosition)
: base(startingLocation)
{
HorizontalEndPosition = horozontalEndPosition;
VerticalEndPosition = verticalEndPosition;
}
public Rectangle(int x, int y, int lineThickness, int horozontalEndPosition, int verticalEndPosition)
: base(x, y)
{
LineThickness = lineThickness;
HorizontalEndPosition = horozontalEndPosition;
VerticalEndPosition = verticalEndPosition;
}
#endregion
#region Properties
[XmlIgnore]
public int LineThickness { get; set; }
[XmlIgnore]
public int HorizontalEndPosition {get; set;}
[XmlIgnore]
public int VerticalEndPosition { get; set; }
public override string CommandString
{
get
{
return String.Format("X{0},{1},{2},{3},{4}", X, Y, LineThickness, HorizontalEndPosition, VerticalEndPosition);
}
set
{
GenerateCommandFromText(value);
}
}
#endregion
#region Helpers
private void GenerateCommandFromText(string command)
{
if (!command.StartsWith(GetFactoryKey()))
throw new ArgumentException("Command must begin with " + GetFactoryKey());
string[] commands = command.Substring(1).Split(',');
this.X = int.Parse(commands[0]);
this.Y = int.Parse(commands[1]);
this.LineThickness = int.Parse(commands[2]);
this.HorizontalEndPosition = int.Parse(commands[3]);
this.VerticalEndPosition = int.Parse(commands[4]);
}
#endregion
#region Members
public override void Paint(Graphics g, Image buffer)
{
using (Pen p = new Pen(Color.Black, LineThickness))
{
g.DrawRectangle(p, new System.Drawing.Rectangle(X, Y, HorizontalEndPosition - X, VerticalEndPosition - Y));
}
}
public string GetFactoryKey()
{
return "X";
}
#endregion
}
DrawableItemBase:
public abstract class DrawableItemBase : Epl2CommandBase, IDrawableCommand
{
protected DrawableItemBase()
{
Location = new Point();
}
protected DrawableItemBase(Point location)
{
Location = location;
}
protected DrawableItemBase(int x, int y)
{
Location = new Point();
X = x;
Y = y;
}
private Point _Location;
[XmlIgnore]
public virtual Point Location
{
get { return _Location; }
set { _Location = value; }
}
[XmlIgnore]
public int X
{
get { return _Location.X; }
set { _Location.X = value; }
}
[XmlIgnore]
public int Y
{
get { return _Location.Y; }
set { _Location.Y = value; }
}
abstract public void Paint(Graphics g, Image buffer);
}
Epl2CommandBase:
public abstract partial class Epl2CommandBase : IEpl2Command
{
protected Epl2CommandBase() { }
public virtual byte[] GenerateByteCommand()
{
return Encoding.ASCII.GetBytes(CommandString + '\n');
}
public abstract string CommandString { get; set; }
}
Various Interfaces:
public interface IEpl2GeneralFactoryProduct
{
string GetFactoryKey();
}
public interface IEpl2Command
{
string CommandString { get; set; }
}
public interface IDrawableCommand : IEpl2Command
{
void Paint(System.Drawing.Graphics g, System.Drawing.Image buffer);
}
I have a class Class A, and a class Class B.
class B is a child of class A so that:
public class Class A
{
public DateTime FileStart
{
get
{
return Header.StartTime;
}
set{ }
}
...
...
}
and
public class B : A
{
FileInfo zippedA;
public A myA = null;
internal B(FileInfo mFileInfo)
{
...
//collects the same data as A from the fileinfo such as start time...
...
}
public A getAData()
{
UnZipFile(zippedA);
return myA;
}
...
}
So I'm looking for a way to call getAData() whenever an object of B is called as A for example the list Xlist stores all As and Bs but will be accessed from several places in the code:
SortedList Xlist = new SortedList();
public void GetFrames(DateTime desiredStartTime, DateTime desiredEndTime)
{
for(int fileIdx = Xlist.Values.Count-1; fileIdx >= 0; --fileIdx)
{
//my hope is that there is a way to set up B in it's class to say
// "if I get called as an A, I'll perform getAData() and return myA instead.
A rec = (A)Xlist.GetByIndex(fileIdx);
...
...
}
}
in the above instance I would like for every time an object is pulled from Xlist if its a B but gets caste as an A like so, it automatically calls the getAData() function and returns the resulting A instead of its self. is this possible??
You can make the method in parent class virtual and override it in the child classes. In doing so anywhere you call the method on an instance of type A, it will invoke the method in the derived type if the derived type provides and override, otherwise it will invoke the version in type A.
This is the simplest way, the alternative aren't very attractive. For more information on virtual methods in C# check out this msdn article; http://msdn.microsoft.com/en-us/library/aa645767(v=vs.71).aspx
To do what you think you want to do (I'm pretty sure it's not actually what you want to do) you can do this;
for(int fileIdx = Xlist.Values.Count-1; fileIdx >= 0; --fileIdx)
{
A rec = (A)Xlist.GetByIndex(fileIdx);
if (rec.GetType() == typeof(B))
{
B temp = (B) rec;
rec = temp.getAData();
}
}
Although, again, this makes no sense at all. Here's an example;
public class Car
{
int year;
bool manual;
}
public class Porsche : Car
{
bool specialPorscheOnlyFeature;
Engine enginge;
}
public class Engine
{
string engineType;
}
// in some method
Porsche p = new Porsche();
// to get Car data
int yearOfCar = p.year;
bool isManual = p.manual;
bool specialFeature = p.SpecialPorscheOnlyFeature;
Above is an example of how inheritance works. I don't retrieve an instance of the base class, everything the base class has is baked into the instance of the derived class. You're acting like the base class is some other object the derived class is composed of.
It may not be the best way to do it, but would this not work?
class File
{
public string FileInfo = "";
public override string ToString()
{
return FileInfo;
}
public virtual File GetRaw()
{
return this;
}
}
class ZippedFile : File
{
public File Unzip()
{
// Do actual unzip here..
return new File { FileInfo = FileInfo.Substring(0,8) };
}
public override File GetRaw()
{
return Unzip();
}
}
class Program
{
static void Main(string[] args)
{
List<object> files = new List<object>();
files.Add(new File { FileInfo = "BeepBoop" });
files.Add(new ZippedFile { FileInfo = "BeepBoopfQAWEFRLQER:LKAR:LWEasdfw;lekfrqW:ELR" });
files.Add(new File { FileInfo = "BoopBeep" });
files.Add(new ZippedFile { FileInfo = "BoopBeepAWSLF:KQWE:LRKsdf;lKWEFL:KQwefkla;sdfkqwe" });
foreach(var f in files)
{
File rawFile = ((File)f).GetRaw();
Console.WriteLine(rawFile);
}
Console.ReadKey();
}
}
I'm having a small design issue and wanted to consult.
Lets say we have the following class hierarchy:
abstract class A
{
}
class B : A
{
}
class C: A
{
}
I want that both B and C have a certain field x so that it's value is different between the classes but shared among all instances of the same class (i.e: if b1, b2 are instances of B and c1,c2 instances of C then b1.x = b2.x and c1.x = c2.x and b1.x != c1.x).
Is there an elegant way to do this by taking advantage of the fact that both B, C derive from the same base class or do I have to create a static field x in both classes?
Thanks in advance.
You mean like this?
abstract class A
{
static Dictionary<Type, int> all_x;
protected int X {
get { return all_x[GetType()]; }
set { all_x[GetType()] = value; }
}
}
If it has to be a field so you can pass by reference:
abstract class A
{
class SharedType { int x; }
static Dictionary<Type, SharedType> all_shared;
protected SharedType Shared {
get
{
Type t = GetType();
SharedType result;
if (!all_shared.TryGetValue(t, out result) {
result = new SharedType();
all_shared.Add(t, result);
}
return result;
}
}
}
Also, we can improve performance by doing the lookup only once per instance:
abstract class A
{
class SharedType { int x; }
static Dictionary<Type, SharedType> all_shared;
protected SharedType Shared;
A() {
Type t = GetType();
if (!all_shared.TryGetValue(t, out Shared) {
Shared = new SharedType();
all_shared.Add(t, Shared);
}
}
}
What should those values be for the field x? If you need to specify that the value of x for A should be "a", the value of x for B should be "b" etc., then you will have to specify the values "a", "b", ... somewhere and then you mught as well just use:
abstract class A {
public static int x = 1; // Just using "int" as example.
}
class B : A {
public static int x = 2;
}
If you do not care what the values are (which type do you need then) but merely want the values to be "different", then instead of using fields you could use something like:
abstract class A {
public int X { get { return this.GetType().GetHashCode(); } }
}
This does not take hash collisions into account, but maybe it is useful anyway?
What is it you are trying to achieve?
To build on Ben Voigt's first answer, I think what you want for your base class is this:
public abstract class A
{
private static ConcurrentDictionary<Type, int> _typeIDs = new ConcurrentDictionary<Type, int>();
private static int _nextID = 1;
public int TypeID
{
get
{
return _typeIDs.GetOrAdd(this.GetType(), type => System.Threading.Interlocked.Increment(ref _nextID));
}
}
}
public abstract class A
{
public abstract int Value { get; }
}
public class B : A
{
public override int Value { get { return 1; } }
}
public class C : A
{
public override int Value { get { return 2; } }
}
The only way I know to do this is if you make class A a generic class, i.e. class A<T>. Then have class B implement a different type for the generic type than the generic type that Class C implements.
If you don't use generics, then I believe this is impossible in .NET.
Here is an example where lets say the value you were interested in was a data structure with members int Foo and string Bar. One derive class could implement the an identical structure (but different derived type) than the other - the two structures would implement the same interface.
interface IAvalue
{
int Foo { get; set;}
string Bar {get; set;}
}
struct BValue
: IAvalue
{
public int Foo { get; set; }
public string Bar { get; set; }
}
struct CValue
: IAvalue
{
public int Foo { get; set; }
public string Bar { get; set; }
}
abstract class A<T> where T : IAvalue
{
protected static T myValue;
}
class B : A<BValue>
{
static B()
{
myValue.Foo = 1;
myValue.Bar = "text1";
}
}
class C : A<CValue>
{
static C()
{
myValue.Foo = 2;
myValue.Bar = "text2";
}
}
You can use one .net feature: If you have static data members in a generic class, .net creates different instances of static data members for each generic type you use.
So, you can write:
public abstract class A<T> where T : A<T>
{
protected static int myVariable { get; set; }
}
And inherit your classes as:
public class B : A<B>
{
public B()
{
myVariable = 1;
}
public int GetVariable()
{
return myVariable;
}
}
public class C : A<C>
{
public C()
{
myVariable = 2;
}
public int GetVariable()
{
return myVariable;
}
}
Then every instance of B will have shared access to one instance of myVariable and every instance of C will have shared access to another.
So, if you add Set(int a) method:
public void Set(int a)
{
myVariable = a;
}
And run the following code:
static void Main(string[] args)
{
B b1 = new B();
C c1 = new C();
B b2 = new B();
C c2 = new C();
Console.Write("{0}; ", b1.GetVariable()); // 1
Console.Write("{0}; ", b2.GetVariable()); // 1
Console.Write("{0}; ", c1.GetVariable()); // 2
Console.Write("{0}; ", c2.GetVariable()); // 2
Console.WriteLine();
c2.Set(333);
Console.Write("{0}; ", b1.GetVariable()); // 1
Console.Write("{0}; ", b2.GetVariable()); // 1
Console.Write("{0}; ", c1.GetVariable()); // 333
Console.Write("{0}; ", c2.GetVariable()); // 333
Console.ReadLine();
}
You get: 1; 1; 2; 2;
1; 1; 333; 333; output.
I would suggest defining a static Dictionary<Type, Integer[]>, and having the base-class constructor call GetType() on itself and see if it's yet in the static dictionary. If not, create a new single-element array and store it in the dictionary. Otherwise grab the array from the dictionary and store it in an instance field. Then define a property which reads or writes element zero of the array. This approach will achieve the requested semantics for all derivatives and sub-derivatives of the class.