c# polymorphism derive class to other derive class - c#

I have a class for example Tile, with derive classes TileA, TileB... TileF.
Now I want always that class TileF changes with a call into TileE.
And also TileE to TileD, and you can see the patern.
Can I specify it directly in TileF where it changes into.
I'm looking at Activator.CreateInstance(), but this gives me a object class, and not the wanted derive class.
How can I solve this?
I do this in my Main loop, where I specified that Tile tile = TileF;
then i want to do something like: tile.change() and that it changes in a new TileE
Some kind of code:
Class Tile{
public abstract int Number{ get; }
}
Class TileF : Tile{
public override int Number
{
get
{
return 1;
}
}
}
Class TileE : Tile{
public override int Number
{
get
{
return 2;
}
}
}
Class Main{
Tile tile = new TileF;
//change tile to TileE
tile = tile.ToNextTileType();
}

When TileE and TileF are siblings, ie when they derive from a common baseclass, you cannot convert them directly.
There are several possible solutions but you don't provide much detail.
I think that maybe you should not use inheritance. Could a simple enum TileType solve your problem(s)?

You might want to look at interfaces. Interface lets unrelated objects be treated as the same thing when you reference a type of the Interface type e.g.
class ClassOne : ICommon;
class ClassTwo : ICommon;
class ClassThree : ICommon;
ClassOne x = new ClassOne();
ClassTwo y = new ClassTwo();
ClassThree z = new ClassThree();
List<ICommon> data = new List<ICommon>();
data.Add(x);
data.Add(y);
data.Add(z);
foreach(ICommon item in data)
{
item.InterfaceMethodOne();
}
This might not be what you want but it is worth looking into.
James :-)

There is a difference between the static and the dynamic type of an object. The static type of an object can be changed, that is you may write BaseType base = (BaseType)new DerivedType();. Changing the static type of an instance is called casting.
The compiler will restrict the call to methods, fields and properties present in the BaseType and all of its base types. The dynamic type of an object however may never change and in this case base still has the dynamic type DerivedType. The condition if (base is DerivedType) will return true in this case. You can only "change" the dynamic type by instantiating a new object of the target type and copy the desired values to the new instance. This process is called mapping.
Btw, Activator.CreateInstance will only give you an instance of the static type object, but likely with a different dynamic type. You can change the static type by casting it to a type that you know the object should have: (DerivedType)Activator.CreateInstance(typeof(DerivedType)). You can also use the generic variant, then this cast is done within the method: Activator.CreateInstance<DerivedType>(). Semantically there is no difference, except that the generic variant is easier to read.
EDIT:
Does this solve your problem?
public abstract class Tile {
public abstract int Number { get; }
public abstract Tile Advance();
}
public class TileA : Tile {
public override int Number { get { return 1; } }
public override Tile Advance() { return new TileB(); }
}
public class TileB : Tile {
public override int Number { get { return 2; } }
public override Tile Advance() { return new TileC(); }
}
public class TileC : Tile { ... }
You can also define the "state machine" in the abstract class like so:
public abstract class Tile {
public abstract int Number { get; }
public sealed Tile Advance() {
if (this is TileA) {
return new TileB();
else if (this is TileB) {
return new TileC();
}
}
}
Another alternative is of course to model the state machine entirely in one object:
public enum TileState { TileA, TileB, TileC };
public class Tile {
private TileState state = TileState.TileA; // initial state
public int Number {
get {
switch (state) {
case TileState.TileA: return 1;
case TileState.TileB: return 2;
...
default: return -1; // or throw exception
}
}
}
public void Advance() {
switch (state) {
case TileState.TileA: state = TileState.TileB; break;
case TileState.TileB: state = TileState.TileC; break;
...
default: // exception ?
}
}
}
In the last example, the behavior of your object changes depending on the state variable. It's not a new instance, but it can do something completely different. I hope something of this could help.

I made an error in designing TileF/TileE etc. It was good enough to make a TileN, with a property that is replacing the inner working of a tile. This way I don't have to substitute a class, and thus avoiding this problem.

Related

C# cast polymorphic object into specific type without knowing what that 'specific type' is

Thanks ahead, community!
As the title describes, I would like to cast an object that is in parent type to a child type, which is actually a child type, whilst this 'specific type' cannot be known until runtime.
Lets say I have following data holder:
public class Holder {}
public class Holder<T> : Holder
{
public T Value;
}
And this Holder (not Holder<T>) will be given to some script at runtime.
I need to cast this Holder into Holder<T> (eg, Holder<string>), so that I can access the Value : T.
For now, I can just mannually add casting cases and their coresponding methods to process it, but time by time there will be more types that goes into this Holder<T>, and it would become imposible to manage in this way.
Is there a way to accomplish this objective?
This Holder must not be flattened, as it is being used in a context as below:
public class SomeNode
{
protected Holder holder;
}
public class SomeNode<T> : SomeNode
{
public SomeNode<T>()
{
holder = new Holder<T>();
}
}
I have no clue how to approach this, nor a search keyword to catch a hint about this.
Automatic suggestions came up before posting seems not my case, which were:
C# Create (or cast) objects of a specific type at runtime
C# Accessing generic Method without knowing specific type
Edit
Thanks to #W.F., I could start searching with an effective keyword 'dynamic object', and I ended up finding System.Reflection as my desired soultion.
It looks like as belows and currently it solves my immediate issue:
holder.GetType().GetProperty("GetValue").Invoke(holder, null);
But as pointed out by #OlivierJacot-Descombes, my structure and a way of using it is breaking a purpose of polymorphism. Therefore I still need a better solution, which would do a job I am looking for and also not breaking polymorphism.
Possible walkaround that comes in my head is that, first, create a method GetValue() in Holder, and also create class that inherits from Holder to implement this method:
public class Holder
{
public virtual string GetValue() => "";
}
public class Holder<T> : Holder
{
public T Value;
}
public class FloatHolder : Holder<float> //for example
{
public override string GetValue() => Value.ToString();
}
Second, change node structure like:
public class SomeNode
{
protected Holder holder;
}
public class SomeNode<T> : SomeNode {}
public class FloatNode : SomeNode<float>
{
public FloatNode()
{
holder = new FloatHolder();
}
}
Then, I can do like:
public class EchoNode : SomeNode
{
public void Tick()
{
Console.WriteLine(holder.GetValue());
}
}
Seems like too many classes are being created, but it also seems not breaking polymorphism.
Looking for further advices. Again, Thanks!
Edit#2
I already said this in the comment, but for better readability, I write this here as well.
Both Dynamic Object and System.Reflection were easy and fitting solutions which I was looking for, but they weren't best solutions in general.
At the beginning I was misinterpreting #OlivierJacot-Descombes 's answer. He was overall pointing out two impediments: first, my class structure is breaking polymorphism, and second, reflection is slow (and later I noticed, dynamic object as well). I didn't catch the last bit at first so I went through a long way.
Moreover, turned out, I couldn't use dynamic object for my project context, as I am not using normal C# but a Unity C#. Technically I can, but they don't blend well.
Thankfully, my revised solution was acceptable. Therefore I decided to select #OlivierJacot-Descombes 's post as an answer. But I hope, still, people would approach and leave me an good advices.
Thank you all.
If you need to cast to a specific type, you are doing polymorphism wrong. Of course you could do something like this:
switch (holder)
{
case Holder<string> stringHolder:
DoStringThing(stringHolder.Value);
break;
case Holder<int> intHolder:
DoIntThing(intHolder.Value);
break;
...
}
See also: Switch statements with patterns.
However, the idea behind polymorphism is to be able to do things without having to know the specific type. Therefore, re-design the holder classes and have them do the type specific thing themselves:
public abstract class Holder
{
public abstract void DoThing();
}
public abstract class Holder<T> : Holder
{
public abstract T Value { get; }
}
Some examples of specific types:
public class StringHolder : Holder<string>
{
public StringHolder(string value)
{
Value = value;
}
public override string Value { get; }
public override void DoThing()
{
Console.WriteLine($"String of length {Value.Length} is \"{Value}\"");
}
}
public class IntHolder : Holder<int>
{
public IntHolder(int value)
{
Value = value;
}
public override int Value { get; }
public override void DoThing()
{
Console.WriteLine($"The integer {Value} is {(Value % 2 == 0 ? "even" : "odd")}");
}
}
Now you can simply write
holder.DoThing();
... without having to cast.
Update
Your edited question indeed shows a polymorphic version.
Here I want to present another approach which merges Holder and Holder<T> in a single class through the use of interfaces.
public interface IHolder
{
object Value { get; set; }
}
public interface IHolder<T> : IHolder
{
new T Value { get; set; } // The new keyword hides the inherited property.
}
public class Holder<T> : IHolder<T>
{
object IHolder.Value
{
get => Value; // Returns T Holder<T>.Value as object.
set => Value = value is T t ? t : default; // Sets T Holder<T>.Value.
}
public T Value { get; set; }
}
Holder<T> now implements a "neutral" Value property declared in IHolder based on the object type. Since it implements it explicitly (i.e., instead of public object Value we write object IHolder.Value), this property is hidden, unless it is accessed through the interface. This allows you, for example, to declare a List<IHolder> and to retrieve different kinds of Holder<T> values with list[i].Value as object.
But you have a variable Holder<float> floatHolder, you can get the strongly typed float value.
Note that this still allows you do derive more specific types like class FloatHolder : Holder<float>, but it might not even be necessary.
If you intend to work only with derived types, you can mark Holder<T> as abstract and also all the members that must be implemented by the deriving classes. This makes it impossible to create an instance of Holder<T> with new and also allows you to declare abstract methods without body.
community! It's a good question. That was interesting.
I think this is simple solve for this question.
We just need to create a simple constructor like below
public class Holder
{
public string SomeData; // just example data
public Holder()
{
}
public Holder(Holder someData)
{
SomeData = someData.SomeData;
}
}
public class Holder<T> : Holder
{
public T Value;
public Holder(Holder a, T t = default)
:base(a)
{
Value = t;
}
}
public class Programm
{
void Main()
{
var h = new Holder();
var g = new Holder<string>(h);
}
}

Changing the default value of an instance variable

Suppose I have these codes (and the classes are in the same namespace):
class Animal
{
int numberOfLegs = 4; // initialized
public int returnNumberOfLegs()
{
return numberOfLegs;
}
}
class Snake
{
internal Animal myAnimalObject = new Animal();
myAnimalObject.numberOfLegs = 0; // why is this line not allowed?
}
class Program
{
public static void Main(string [] args)
{
Snake mySnakeObject = new Snake();
Console.WriteLine("Snake");
Console.WriteLine("Number of Legs: {0}", mySnakeObject.myAnimalObject.returnNumberOfLegs());
}
}
Observe the class Snake. When I place these 2 lines of code in Main(), it is possible/allowed and will work if I declare the variable numberOfLegs with the right access modifier. Why can't I do it in the class Snake itself? What should I do to allow it?
Note that the 2nd line of code from class Snake is invalid and these are the errors it produced:
1) Error 1 Invalid token '=' in class, struct, or interface member declaration
2) Error 2 'myNamespaceName.Snake.myAnimalObject' is a 'field' but is used like a 'type'
Thanks. I just want to learn about this.
Edit:
Okay, thanks guys. I know about constructors and inheritance, but somehow, I'm being forced to do it "the hard and not-so-smart" way, for learning purposes(?). And that I even had to set the default value to 4. Thank you for your replies. Plus, I just made up these classes.
Because executable code should be placed either in constructor or in some method/property.
You cannot place code just inside the class, put it in the constructor.
class Snake
{
internal Animal myAnimalObject = new Animal();
public Snake()
{
myAnimalObject.numberOfLegs = 0;
}
}
When you write
internal Animal myAnimalObject = new Animal();
in the class body, it's a kind of a syntax sugar; compiler will create constructor and put your code line inside it.
and it will look like
class Snake
{
internal Animal myAnimalObject;
public Snake()
{
myAnimalObject = new Animal();
myAnimalObject.numberOfLegs = 0;
}
}
First of all, you can't do this in the class initializer:
myAnimalObject.numberOfLegs = 0;
Since you're not setting a class member itself, but rather interacting with a class member, you'd have to do it in the constructor:
public Snake()
{
myAnimalObject.numberOfLegs = 0;
}
Also, in order to access numberOfLegs it would need to be internal or public:
internal int numberOfLegs = 4; // initialized
More to the point of the whole scenario however, this seems like a very odd abstraction. Though part of me applauds the use of composition instead of inheritance, this seems more like a case where inheritance is warranted. It seems that Animal really shouldn't be initializing any value for numberOfLegs by default. Indeed, Animal shouldn't even be a concrete object given the real-world concepts being modeled. Instead, I might try something like:
abstract class Animal
{
public abstract int NumberOfLegs { get; }
}
class Snake : Animal
{
public override int NumberOfLegs { get { return 0; } }
}
The idea being that a Snake is an Animal, that an Animal by itself can't exist unless it's a specific type of Animal, and that each individual type of Animal internally controls its own values and all the abstract Animal class does is define what those values need to be.
You should use inheritance instead. Make Animal an abstract class, base class for all animals. Composition (what you use now) does not make much sense in this case.
abstract class Animal
{
protected int numberOfLegs = 4; // default number of legs
public int NumberOfLegs { get { return numberOfLegs; } }
public Animal(int legs)
{
numberOfLegs = legs; // initialize number of legs
}
}
All concrete animals then derive from this class.
class Snake : Animal
{
public Snake() : base(0) // specify that number of legs is 0
{
}
}
The base(0) is a call to a base class constructor, so you are calling Animal(int legs) with an argument 0.
Do it like this:
abstract class Animal
{
private readonly int numberOfLegs;
protected Animal(int nrLegs = 4)
{
numberOfLegs = nrLegs;
}
public int returnNumberOfLegs()
{
return numberOfLegs;
}
}
class Snake : Animal
{
public Snake() : base(0)
{
}
}

c# abstract classes

i have to create a fake DMV program that calculates annual fees, for commercial and private vehicles. Those two classes will be abstract and they will polymophism from a class named all vehicles.
My instructor wants only one object created the entire program(in main) but since my top 3 tier classes are abstract. I can't create an object with them i.e. vehicles = new vehicles();
so my question is how do i create only one object since they are abstract? If you have any questions feel free to ask, I might have not explained this well...
Your class structure will look something like:
abstract class Vehicle
{
protected abstract int BaseFee { get; }
protected abstract int ExtraFee { get; }
public int CalculateFee()
{
return BaseFee + ExtraFee;
}
}
abstract class CommercialVehicle : Vehicle
{
protected override int BaseFee
{
return 100;
}
}
class LightDutyTruck : CommercialVehicle
{
protected override int ExtraFee
{
return 50;
}
}
class Semi : CommercialVehicle
{
protected override int ExtraFee
{
return 150;
}
}
[etc...]
abstract class PrivateVehicle : Vehicle
{
protected override int BaseFee
{
return 25;
}
}
class Sedan : PrivateVehicle
{
protected override int ExtraFee
{
return 15;
}
}
and so on, for each class. In your Main method, you would create the instance based on input, but your actual variable would be declared as type Vehicle. The actual calculation will take effect based on the instance that you create:
Vehicle v;
switch(input)
{
case "semi":
v = new Semi();
break;
case "truck":
v = new LightDutyTruck();
break;
...
}
int fee = v.CalculateFee();
You seem to be a bit confused. "All Vehicles" should be abstract. "Commercial Vehicle" and "Private Vehicle" should not be abstract, unless there are concrete subclasses of those two.
You may also not be understanding what your instructor means by "only one object", since that doesn't make sense.
Maybe you are to make one object which represents the DMV, but the definition of that object includes instances of other objects.
class DMV {
private List<Vehicle> vehicles = new List<Vehicle>();
...
}
Your instructor may want you to instantiate multiple objects through a reference to the abstract base class:
Vehicle conveyance;
conveyance = new PrivateVehcicle();
conveyance.Drive();
conveyance.Stop();
// or whatever ...
conveyance = new CommercialVehcicle();
conveyance.Drive();
conveyance.Stop();
i.e. you have a single object reference (conveyance) that behaves polymorphically depending on the concrete type you've instantiated.

Can I force a subclass to declare a constant?

I want to force subclasses to define a constant value.
Like
const string SomeConstantEverySubclassMustDefine = "abc";
I need that because I need to have it tied to the Type, rather than to the instance and you can't override static Methods/Properties iirc.
I'd really like to have a compile-time check for those constants.
Let me explain in more detail:
Some classes in our Domain-Model are special, you can take certain actions for them, depending on the type. Thus the logic is tied to the type. The action to be taken requires a string tied to the type. I sure could create an instance everytime as a workaround and declare an abstract property, but that's not what I want. I want to enforce the declaration of the string at compile-time, just to be sure.
No, you can't. I would suggest you make your base class abstract, with an abstract property which you can fetch when you want. Each child class can then implement the property just by returning a constant if it wants. The downside is that you can't use this within static methods in the base class - but those aren't associated with the child classes anyway.
(It also allows child classes to customise the property per instance as well, if necessary... but that's rarely an actual problem.)
If this doesn't do enough for you, you might want to consider a parallel type hierarchy. Basically polymorphism simply doesn't happen in a type-specific way in .NET; only in an instance-specific way.
If you still want to do this and fetch it with reflection, I suggest you just write unit tests to ensure that the relevant constants are defined. When you get beyond what the type system can describe, that's often the best you can do.
Make an abstract property with only a get. That's what I think you could do to enforce a class has a value. Then you can just return a constant in the property.
Example:
Base class:
public abstract string MyConst { get; }
Derived class:
public override string MyConst {
get { return "constant"; }
}
Here is how I made mine work. I used Attribute as others have suggested.
public class ObjectAttribute : Attribute
{
public int ObjectSize { get; set; }
public ObjectAttribute(int objectSize)
{
this.ObjectSize = objectSize;
}
}
public abstract class BaseObject
{
public static int GetObjectSize<T>() where T : IPacket
{
ObjectAttribute[] attributes = (ObjectAttribute[])typeof(T).GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
}
[ObjectAttribute(15)]
public class AObject : BaseObject
{
public string Code { get; set; }
public int Height { get; set; }
}
[ObjectAttribute(25)]
public class BObject : BaseObject
{
public string Code { get; set; }
public int Weight { get; set; }
}
If you would like instance access to the attribute just add it to the base abstract class.
public abstract class BaseObject
{
public static int GetObjectSize<T>() where T : IPacket
{
ObjectAttribute[] attributes = (ObjectAttribute[])typeof(T).GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
public int ObjectSize
{
get
{
ObjectAttribute[] attributes = (ObjectAttribute[])GetType().GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
}
}
Usage of the constants
int constantValueA = AObject.GetObjectSize<AObject>();
int constantValueB = BObject.GetObjectSize<BObject>();
AObject aInstance = new AObject();
int instanceValueA = aInstance.ObjectSize;
New idea
Here's a sort of weird idea: instead of using inheritance directly, you create a separate class to provide a constant value for every type deriving from some type T. The constructor for this type uses reflection to verify that every derived type has indeed been supplied a value.
public abstract class Constant<T, TConstant>
{
private Dictionary<Type, TConstant> _constants;
protected Constant()
{
_constants = new Dictionary<Type, TConstant>();
// Here any class deriving from Constant<T, TConstant>
// should put a value in the dictionary for every type
// deriving from T, using the DefineConstant method below.
DefineConstants();
EnsureConstantsDefinedForAllTypes();
}
protected abstract void DefineConstants();
protected void DefineConstant<U>(TConstant constant) where U : T
{
_constants[typeof(U)] = constant;
}
private void EnsureConstantsDefinedForAllTypes()
{
Type baseType = typeof(T);
// Here we discover all types deriving from T
// and verify that each has a key present in the
// dictionary.
var appDomain = AppDomain.CurrentDomain;
var assemblies = appDomain.GetAssemblies();
var types = assemblies
.SelectMany(a => a.GetTypes())
.Where(t => baseType.IsAssignableFrom(t));
foreach (Type t in types)
{
if (!_constants.ContainsKey(t))
{
throw new Exception(
string.Format("No constant defined for type '{0}'.", t)
);
}
}
}
public TConstant GetValue<U>() where U : T
{
return _constants[typeof(U)];
}
}
Basic example:
public class BaseType
{
public static Constant<BaseType, string> Description { get; private set; }
static BaseType()
{
Description = new BaseTypeDescription();
}
}
public class DerivedType : BaseType
{ }
internal sealed class BaseTypeDescription : Constant<BaseType, string>
{
public BaseTypeDescription() : base()
{ }
protected override DefineConstants()
{
DefineConstant<BaseType>("A base type");
DefineConstant<DerivedType>("A derived type");
}
}
Now I have code that allows me to do this:
var description = BaseType.Description;
// returns "A base type"
string baseTypeDescription = description.GetValue<BaseType>();
// returns "A derived type"
string derivedTypeDescription = description.GetValue<DerivedType>();
Original answer
You may not like it, but the closest way to accomplish this is by declaring an abstract read-only (no set) property.
If you've got an instance of your subclass, then this can work just as well as a constant, even though it is technically instance-level (it will just be the same for all instances of the given class).
Consider, for instance, IList.IsReadOnly. In most cases this is actually a property that tells you about the underlying class implementation, as opposed to any state specific to a particular instance. (It may be an interface member as opposed to an abstract class member, but it's the same idea.)
If you are trying to access it statically, well... then you're out of luck. But in this case I fail to see how you'd obtain the value without using reflection anyway. Maybe that's your intention; I don't know.
You could have a static method in the base class called, for instance "Register", that is passed a Type and a constant value, with the intention being that it is called by the class constructors of the subtypes. Then, add a check in all of your base class constructors that the object being constructed is of a registered type.
abstract class Base
{
private static Dictionary<Type, string> _registry = new Dictionary<Type, string>();
protected static void Register(Type t, string constVal)
{
_registry.Add(t, constVal);
}
protected Base()
{
if(!_registry.ContainsKey(this.GetType()))
throw new NotSupportedException("Type must have a registered constant");
}
public string TypeConstant
{
get
{
return _registry[this.GetType()];
}
}
}
class GoodSubtype : Base
{
static GoodSubtype()
{
Base.Register(typeof(GoodSubtype), "Good");
}
public GoodSubtype()
: base()
{
}
}
class Badsubtype : Base
{
public Badsubtype()
: base()
{
}
}
And then elsewhere, you can construct GoodSubtype instances, but trying to construct a Badsubtype gets an exception. I think a runtime error at construction is the soonest you can get an error with this type of scheme.
(You'd want to use ConcurrentDictionary for your registry if threading is involved)
There's one other method that hasn't been covered and it uses the new modifier to hide consts values in the base class. In a way, it's similar to Nap's solution, but doesn't allow per-instance access and therefore doesn't allow for polymorphic access within the base class. This solution is only useful if you want to have constant value defined but wish to have the option of changing it to different values in different subclasses.
static void Main(string[] args)
{
Console.WriteLine("BaseClass.MyConst = {0}, ClassA.MyConst = {1}, ClassB.MyConst = {2}", BaseClass.MyConst, ClassA.MyConst, ClassB.MyConst);
Console.ReadKey();
}
class BaseClass
{
public const int MyConst = 1;
}
class ClassA : BaseClass
{
public new const int MyConst = 2;
}
class ClassB : BaseClass
{
}

How to make an Abstract Base class IComparable that doesn't compare two separate inherited classes?

(C#, VS2008) In a program I'm working on, I've got lots of objects that all have an ID and implement IComparable so that List<>-s of the various objects are easily searchable by ID. Since I hate copy/pasting code, I thought I'd abstract that bit of functionality down to a base class, like so:
using System;
namespace MyProg.Logic
{
abstract class IDObject : IComparable<IDObject>
{
private int miID;
public int ID
{
get { return miID; }
set { miID = value; }
}
public IDObject(int ID)
{
miID = ID;
}
#region IComparable<IDObject> Members
int IComparable<IDObject>.CompareTo(IDObject other)
{
return miID.CompareTo(other.miID);
}
#endregion
}
}
The drawback I see to that is that two separate classes that each inherit it would be directly comparable using .CompareTo() and I was hoping to enforce that each class that inherits from IDObject is only Comparable to others of the exact same class. So I was hoping to figure out how to do that and came up with this
using System;
namespace MyProg.Logic
{
abstract class IDObject : IComparable<T> where T : IDObject
{
private int miID;
public int ID
{
get { return miID; }
set { miID = value; }
}
public IDObject(int ID)
{
miID = ID;
}
#region IComparable<T> Members
int IComparable<T>.CompareTo(T other)
{
return miID.CompareTo(other.miID);
}
#endregion
}
}
But that gives a compile error of "Constraints are not allowed on non-generic declarations"
Looking at it, I'm sure there's a way to do something like that so that each class is only comparable to other instances of that same class, but I can't tease out the syntax.
You can use the Curiously Recurring Template Pattern to solve this problem.
abstract class Base<T> : IComparable<T> where T : Base<T> {
public int Rank { get; set; } // Order instances of derived type T by Rank
public int CompareTo(T other) { return Rank.CompareTo(other.Rank); }
}
class Foo : Base<Foo> {}
class Bar : Base<Bar> {}
static class Program {
static void Main() {
var foo1 = new Foo { Rank = 1 };
var foo2 = new Foo { Rank = 2 };
var bar1 = new Bar { Rank = 1 };
var bar2 = new Bar { Rank = 2 };
Console.WriteLine(foo1.CompareTo(foo2));
Console.WriteLine(bar2.CompareTo(bar1));
//error CS1503: Argument '1': cannot convert from 'Bar' to 'Foo'
//Console.WriteLine(foo1.CompareTo(bar1));
}
}
I think you've got bigger problems than just making sure that the derived class types are the same. You are also saddling the derived class with the responsibility to generate a unique ID. That requires the derived class to be aware what other IDs were assigned previously. Realistically, that requires a class factory. You'll need to enforce that by making the constructor of your abstract class protected.
Not very practical. If the ID is just an opaque number that establishes object identity then consider assigning the ID yourself. Use a static member to keep track of the last assigned one. Now it becomes simple, and you don't have to worry about derived class types anymore.

Categories