Initialize a static parameter at inheritance in c# - c#

I have one base class that is used to declare generic data structures that have a fixed length in a datablock:
public abstract class FixedLengthDataItem
{
// a static field here to store the fixed length?
public sealed void LoadFromBytes(byte[] data)
{
// Check the fixed length here
DoStuff(data, offset);
}
protected abstract void DoStuff(byte[] data);
}
There can be a lot of data structures that have a fixed length and my intent is to describe them in subclasses.
I'd like to know whether there is a possibility to transmit the information about the fixed length when declaring the inheritance in the child classes:
public class ChildClass : FixedLengthDataItem // Specific syntax here?
{
public override void DoStuff(byte[] data)
{
// Some stuff
}
}
I cannot find a syntax like : FixedLengthDataItem(2) or : FixedLengthDataItem<2> that would allow to set the value of a static field that would be declared in the mother class and could be used to "generically" check the length in the LoadFromBytes method (2 in my example).
If there is no way to do it, what could be a smart way to allow anyone to write subclasses making sure that the check that is performed in the LoadFromBytes method checks the right thing?
I thought about something like:
private readonly int _size;
protected FixedLengthDataItem(int size) { _size = size; }
in the base class. And:
public ChildClassFoo() : base(2) { } // or
public ChildClassBar() : base(3) { } // etc.
in the child class(es). But doing this:
a constructor must be declared in each derived class,
more important: a field size will exist in each object whereas the same size applies for all the instances of each derived class which is not very wise I guess.

Here is one way to do it. Not quite as clean as C++ templates but interesting regardless.
public abstract class DataSize
{
protected DataSize(int size)
{
if (size < 0)
throw new ArgumentOutOfRangeException("Must be greater than zero.", nameof(size));
Size = size;
}
public int Size { get; }
}
public abstract class FixedLengthDataItem<TDataSize>
where TDataSize : DataSize, new()
{
public static TDataSize Data { get; } = new TDataSize();
// a static field here to store the fixed length?
public void LoadFromBytes(byte[] data)
{
// Check the fixed length here
if (data.Length != Data.Size)
{
throw new ArgumentException($"Data has size {data.Length} but a size of {Data.Size} was expected.", nameof(data));
}
DoStuff(data);
}
protected abstract void DoStuff(byte[] data);
}
public sealed class ItemData345 : DataSize { public ItemDataSize() : base(345) { } }
public sealed class CustomItem : FixedLengthDataItem<ItemData345>
{
protected override void DoStuff(byte[] data)
{
throw new NotImplementedException();
}
}
Lets say you have 3-4 classes of this size it actually pays of syntax wise.
Space wise is a different story, you'll need so many instances for this to truly be worth it but it is an interesting experiment.

For what you're describing, putting the size on the base class and then specifying it in the derived classes is better than using any sort of static field.
As you showed in your question:
public ChildClassFoo() : base(2) { }
public ChildClassBar() : base(3) { }
a constructor must be declared in each derived class
You've declared two derived classes in your example without constructors.
a field size will exist in each object whereas the same size applies for all the instances of each derived class which is not very wise I guess.
That would be exactly, precisely the point of putting that field in the base class. If every class that inherits from it needs a field size then what you're doing with the base class ensures that. It doesn't matter if two different classes happen to have the same field size.

Related

How declare a generic class field inside abstract class

I would like to declare a generic field inside PakFileFormat class in order to be replaceable with concrete types in derived classes.
This will be fine:
public class Pak10File : PakFileFormat
{
public Pak10File()
{
this.toc = new PakFileToc<Pak10FileEntry>();
}
}
How to fix this ?
Thanks.
Related classes
public abstract class PakFileEntry { }
public class Pak10FileEntry : PakFileEntry
{
public long size; // 8 bytes
public long csize; // 8 bytes
public long offset; // 8 bytes
public byte fname_len; // 1 byte
public char[] fname; // variable
}
public class PakFileToc<T> where T : PakFileEntry { }
public abstract class PakFileFormat
{
protected PakFileToc<T>; // ----- This does not compile.
}
You would need to make PakFileFormat generic also in order to make that compile.
In order for this to be useful though, you will probably need to make PakFileFormat implement some kind of non-generic interface.
It is hard to give more detail than this without knowing exactly what you need PakFileFormat to actually do, or how it will be used.
public abstract class PakFileFormat<TPakFile> where TPakFile : PakFileEntry
{
protected PakFileToc<TPakFile> toc;
}
The sub-classes would then look something like:
public class Pak10File : PakFileFormat<Pak10FileEntry>
{
public Pak10File()
{
this.toc = new PakFileToc<Pak10FileEntry>();
}
}

Is there a good way to handle private static fields in a generic type in C#?

I am trying to figure out a way I can make use of private static fields in a generic class. This is the obvious way to do it (fiddle). It won't compile because Field is not accessible in BaseChild, and ideally I wouldn't want it to be accessible there:
public class Base<T>
{
private static readonly string Field = "field";
public Base()
{
Console.WriteLine(Field);
}
}
public class BaseChild : Base<string>
{
public BaseChild()
{
Console.WriteLine(Field);
}
}
The problem with this solution is that there is a different Field for each generic type, instead of being shared across them.
I have seen this answer where it says that JetBrains recommends a solution for static fields across generic types:
If you need to have a static field shared between instances with different generic arguments, define a non-generic base class to store your static members, then set your generic type to inherit from this type.
This makes sense for the case where you have public or protected static fields in the base class that you want to share across any child class like this example (fiddle):
public abstract class Base
{
protected static readonly string Field = "field";
}
public class Base<T> : Base
{
public Base()
{
Console.WriteLine(Field);
}
}
public class BaseChild : Base<string>
{
public BaseChild()
{
Console.WriteLine(Field);
}
}
However, what about the case where you want to use a private static field? I would guess that this is not possible since private means only accessible to the class it's declared in and I think that since the generic class is really just a template to create a class, that any private field could only ever be shared by each class, not across all the classes created by the template.
Do I have to just put the private field in the generic class (example 1) and accept it as at least a workable solution for what I want, or is there another way I can accomplish this?
First off -- private is doing exactly what it's made to do: to restrict access to only the type it was declared in. Keep in mind that instantiations of a generic type are all distinct types. You shouldn't be wanting to work around this.
If I understand your question correctly, you can accomplish what you want by using protected with an extra level of inheritance:
class EvenMoreBase
{
protected static readonly string Field = "field";
}
class Base<T> : EvenMoreBase
{
public Base()
{
Console.WriteLine(Field);
}
}
class BaseChild : Base<string>
{
public BaseChild()
{
Console.WriteLine(Field);
}
}
Now each of your Base<T> will share the same instance of Field.
You're correct in your thoughts on private within the base class. Whether it is static or not makes no difference.
Here's a little example:
using System;
public class Program
{
public static void Main()
{
Bar b = new Bar(); // Prints "Foo"
// Console.WriteLine(Foo.BaseField); // Compile error
}
}
public class Foo
{
protected static readonly string BaseeField = "Foo";
}
public class Bar : Foo
{
public Bar()
{
Console.WriteLine(Foo.BaseeField);
}
}
Marking it protected is useful, if you'd like only your children to be able to access it. And leaving it static is how you'd keep only one instance around for all children of the base Foo class.
This is something I came up with that I think actually does what I want better than the initial example I put in my question. It shares a single static field across all the generic types, and it is inaccessible from children of the Base generic class.
public static class Base
{
private static string Field = "field";
public class Base2<T>
{
public Base2()
{
// Field is accessible here, but is the same across all generic classes
Console.WriteLine(Field);
}
}
}
public class BaseChild : Base.Base2<string>
{
public BaseChild()
{
//Field is not accessible here, and I don't really want it to be
//Console.WriteLine(Field);
}
}

inheritance of abstract class with static property in C#

Short version:
I have an abstract class A. It has a method that needs to know the value of a static class property that is specific to each subclass. The name and type is the same, just the value can be unique for each subclass.
Can I define this static property in the base class A to be able to access it with methods defined in A, but keeping the property's values of different subclasses unrelated?
Or how would I implement something like that?
Long version:
Let's say I have an abstract base class for data models. It has a public property Id (Int32).
I would like to implement a constructor in the base class that generates a new ID based on the last assigned ID for objects of a subclass.
The reason is that the real IDs are assigned automatically by the database, but each data model object already has to have a unique ID when it gets constructed without being written to the database yet. As the database assigns only positive integers as ID, my plan is to assign newly created data model objects a temporary, unique negative ID. As soon as the object gets written, the ID will get changed to the real one.
As I have quite a few different data model classes all deriving from my abstract base class, I thought it would be good to include that functionality there to not duplicate it. But each subclass has to have their own counter that points to the next free negative ID, as the different classes' IDs are unrelated.
So I need a static property in each subclass storing this class' last assigned temporary ID, but the mechanism to assign it is always the same and could be implemented into the abstract base class' constructor. However, I can't access a property from the base class that has to be implemented by the subclasses, which means I have to define it in the base class. But will this static property then be global for all subclasses, which is not what I want?
How can I implement this temporary ID counter the most elegant way?
Simplified code example:
public abstract class ModelBase
{
public Int32 Id { get; set; }
protected static Int32 LastTempId { get; set; } = 0;
public ModelBase()
{
Id = --LastTempId;
}
}
public class Model1 : ModelBase
{
public Model1 () : base ()
{
// do something model1-specific
}
}
public class Model2 : ModelBase
{
public Model2() : base()
{
// do something model2-specific
}
}
If I implement it like this, I fear that for both subclasses model1 and model2, the inherited static property LastTempId will be the same instance. But I want a separate counter for each subclass while still using it in the base class constructor.
Short answer
The sub-classes cannot have different values for the static property because the static property is a property of the class, not of it's instances, and it's not inherited.
Long answer
You could implement a single counter on the abstract class as a static property and have one constructor of the abstract class using it.
EDIT: To save different counters for each sub-class you could use a static dictionary mapping a Type (sub-class) to a counter.
public abstract class A<T>
{
public static Dictionary<Type, int> TempIDs = new Dictionary<Type, int>();
public int ID { get; set; }
public A()
{
if (!TempIDs.ContainsKey(typeof(T)))
TempIDs.Add(typeof(T), 0);
this.ID = TempIDs[typeof(T)] - 1;
TempIDs[typeof(T)]--;
}
}
public class B : A<B>
{
public string Foo { get; set; }
public B(string foo)
: base()
{
this.Foo = foo;
}
}
public class C : A<C>
{
public string Bar { get; set; }
public C(string bar)
: base()
{
this.Bar = bar;
}
}
B b1 = new B("foo");
B b2 = new B("bar");
C c1 = new C("foo");
C c2 = new C("foo");
b1.ID would be -1, b2.ID would be -2, c1.ID would be -1 and c2.ID would be -2
First of all, my humble opinion is entities shouldn't be responsible of assigning their own unique identifier. Keep a clear separation of concerns.
There should be another player in that game that should assign those temporary unique identifiers (either if they're negative or positive integers).
Usually, that so-called other player is an implementation of repository design pattern which is responsible of translating the domain (your models) into the definitive representation of your data and vice versa.
Usually a repository has a method to add objects. And this should be the point where you set these temporary identifiers:
public void Add(Some some)
{
some.Id = [call method here to set the whole id];
}
And, most repository implementations are per entity.
CustomerRepository
InvoiceRepository
...
...but this doesn't prevent you from defining a base repository class which could implement what can be in common when handling some entity types:
public interface IRepository<TEntity> where TEntity : EntityBase
{
// Other repository methods should be defined here
// but I just define Add for the convenience of this
// Q&A
void Add(TEntity entity);
}
public class Repository<TEntity> : IRepository<TEntity>
where TEntity : EntityBase
{
public virtual void Add(TEntity entity)
{
entity.Id = [call method here to set the whole id];
}
}
...and now any class deriving Repository<TEntity> will be able to generate a temporary identifier for their specialized entities:
public class CustomerRepository : Repository<Customer> { }
public class InvoiceRepository : Repository<Invoice> { }
How you could implement the unique and temporary entity identifier as part of the abstract repository class and being able to do so for each specific entity type?
Use a dictionary to store per-entity last assigned identifier implementing a property to Repository<TEntity>:
public Dictionary<Type, int> EntityIdentifiers { get; } = new Dictionary<Type, int>();
...and a method to decrease next temporary identifier:
private static readonly object _syncLock = new object();
protected virtual void GetNextId()
{
int nextId;
// With thread-safety to avoid unwanted scenarios.
lock(_syncLock)
{
// Try to get last entity type id. Maybe the id doesn't exist
// and out parameter will set default Int32 value (i.e. 0).
bool init = EntityIdentifiers.TryGetValue(typeof(TEntity), out nextId);
// Now decrease once nextId and set it to EntityIdentifiers
nextId--;
if(!init)
EntityIdentifiers[typeof(TEntity)] = nextId;
else
EntityIdentifiers.Add(typeof(TEntity), nextId);
}
return nextId;
}
Finally, your Add method could look as follows:
public virtual void Add(TEntity entity)
{
entity.Id = GetNextId();
}
One way to go is reflection, but it takes run-time and is prone to runtime errors. As others mentioned: you cannot force inheriting classes to redeclare some static field and be able to use this field in ancestor class. So I think minimal code redundancy is necessary: each inheriting class should provide it's own key generator. This generator can be kept in static field of the class of course.
(Note this is not necessarily thread-safe.)
class KeyGenerator
{
private int _value = 0;
public int NextId()
{
return --this._value;
}
}
abstract class ModelBase
{
private KeyGenerator _generator;
public ModelBase(KeyGenerator _generator)
{
this._generator = _generator;
}
public void SaveObject()
{
int id = this._generator.NextId();
Console.WriteLine("Saving " + id.ToString());
}
}
class Car : ModelBase
{
private static KeyGenerator carKeyGenerator = new KeyGenerator();
public Car()
: base(carKeyGenerator)
{
}
}
class Food : ModelBase
{
private static KeyGenerator foodKeyGenerator = new KeyGenerator();
public Food()
: base(foodKeyGenerator)
{
}
}
class Program
{
static void Main(string[] args)
{
Food food1 = new Food();
Food food2 = new Food();
Car car1 = new Car();
food1.SaveObject();
food2.SaveObject();
car1.SaveObject();
}
}
This produces:
Saving -1
Saving -2
Saving -1
Just generate a GUID for each object before it gets added to your database. You could have an isAdded flag that tells you the object should be referred to be GUID, or clear the GUID once the object is added. With a GUID you never have to worry that two objects will clash. Also it obviates the need for separate IDs per subclass. I would not reuse the same property for two states as you propose.
https://msdn.microsoft.com/en-us/library/system.guid(v=vs.110).aspx
Well, static classes aren't inherited, so that's out,m and you can't force subclasses to implement a static method, so that's out too.
Rather than putting that method in the class itself, why not have a base interface that you can implement. Then you can have an instance method that can be abstract:
public interface IDataModelFactory<T> where T:ModelBase
{
int GetLastTempId();
}
public Model1Factory : IDataModelFactory<Model1>
{
public int GetLastTempId()
{
// logic for Model1
}
}
public Model2Factory : IDataModelFactory<Model2>
{
public int GetLastTempId()
{
// logic for Model2
}
}
Or if the logic is common to all classes, have an abstract base class with (or without) the interface:
public DataModelFactory<T> : IDataModelFactory<T>
{
public virtual int GetLastTempId()
{
// common logic
}
// other common logic
}
You could even make the factories singletons so you don't have to create instances all the time, and they can even be sub-classes of the model classes so they're closely linked.
As a side note, if you're uncertain what the inheritance/interface relationship would be, I often find it's quicker start with copy/paste reuse and refactor your code to introduce base classes and interfaces. That way you know what the common code is and can refactor that into common methods. Otherwise you are tempted to try and put everything in the base class and use switches or other constructs to change logic based on the derived type.

Can't define static abstract string property

I've run into an interesting problem and am looking for some suggestions on how best to handle this...
I have an abstract class that contains a static method that accepts a static string that I would like to define as an abstract property. Problem is that C# doesn't doesn't support the following (see the ConfigurationSectionName and Current properties):
public abstract class ProviderConfiguration : ConfigurationSection
{
private const string _defaultProviderPropertyName = "defaultProvider";
private const string _providersPropertyName = "providers";
protected static string ConfigurationSectionName { get; }
public static Configuration Current
{
get { return Configuration)ConfigurationManager.GetSection(ConfigurationSectionName); }
}
}
I suppose one way to handle this would be to make ConfigurationSectionName NOT abstract and then create a new definition of ConfigurationSectionName in the derived classes, but that feels pretty hackish. Any suggestions would be most welcome.
Gratias!!!
Static members do not have polymorphism, so they can't be abstract. :(
If that's what you need, consider making a Singleton object, and reading the property off that object.
Just use new to override a static method in a derived class. Nothing that makes new a bad thing to do for virtual methods and properties applies since the type name must be supplied:
public class BaseClass
{
public static int Max { get { return 0; } }
}
public class InteriorClass : BaseClass
{
}
public class DerivedClass : InteriorClass
{
public new static int Max { get { return BaseClass.Max + 1; } }
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("BaseClass.Max = {0}", BaseClass.Max);
Console.WriteLine("InteriorClass.Max = {0}", InteriorClass.Max);
Console.WriteLine("DerivedClass.Max = {0}", DerivedClass.Max);
Console.ReadKey();
}
}
Ok, this is not exactly to create an static abstract property, but you can achieve the desired effect.
You can get this by using generics:
public abstract class MyAbstractClass<T>
{
public static string MyAbstractString{ get; set; }
public static string GetMyAbstracString()
{
return "Who are you? " + MyAbstractString;
}
}
public class MyDerivedClass : MyAbstractClass<MyDerivedClass>
{
public static new string MyAbstractString
{
get
{
return MyAbstractClass<MyDerivedClass>.MyAbstractString;
}
set
{
MyAbstractClass<MyDerivedClass>.MyAbstractString = value;
}
}
}
public class MyDerivedClassTwo : MyAbstractClass<MyDerivedClassTwo>
{
public static new string MyAbstractString
{
get
{
return MyAbstractClass<MyDerivedClassTwo>.MyAbstractString;
}
set
{
MyAbstractClass<MyDerivedClassTwo>.MyAbstractString = value;
}
}
}
public class Test
{
public void Test()
{
MyDerivedClass.MyAbstractString = "I am MyDerivedClass";
MyDerivedClassTwo.MyAbstractString = "I am MyDerivedClassTwo";
Debug.Print(MyDerivedClass.GetMyAbstracString());
Debug.Print(MyDerivedClassTwo.GetMyAbstracString());
}
}
So, calling the test class you will get:
"Who are you? I am MyDerivedClass"
"Who are you? I am MyDerivedClassTwo"
So, you have an static method in an abstract class but the abstract value is different for each derived class, nice :D
Ok, so, what's going here? The trick is the generic tag, the compiler is generating a different abstract class for each derived type.
As I said it's not an abstract property, but you get all benefits of abstract static properties, which are programming static functions on your abstract class but using different static parameters per type.
Elsewhere on this page, #Gusman proposes the nice solution distilled here:
abstract class AbstractBase { };
abstract class AbstractBase<T> : AbstractBase
{
public static String AbstractStaticProp { get; set; }
};
class Derived1 : AbstractBase<Derived1>
{
public static new String AbstractStaticProp
{
get => AbstractBase<Derived1>.AbstractStaticProp;
set => AbstractBase<Derived1>.AbstractStaticProp = value;
}
};
class Derived2 : AbstractBase<Derived2>
{
public static new String AbstractStaticProp
{
get => AbstractBase<Derived2>.AbstractStaticProp;
set => AbstractBase<Derived2>.AbstractStaticProp = value;
}
};
Moving the static property from a non-generic to generic class means there is no longer necessarily a single global instance. There will be a unique AbstractStaticProp for each distinct type T, so the idea is that specifying the type of the derived class(es) themselves for T guarantees each of them generates a unique static for themselves. There are a few hazards to note with this, however.
If for some reason it is not acceptable for AbstractBaseClass to be generic, then you've only moved the problem elsewhere (albeit more clearly distilled), because you still have to figure out how to statically call from AbstractBase to AbstractBase<T>.
Mainly, there is nothing to enforce or require that any/every given derived class actually does "implement" the (psudo-) "overridden" static property;
Related to this, since there is no compiler (polymorphic) unification going on here, correct signatures (method name, parameter arity, typing, etc.) for the "overridden" methods aren't enforced either.
Although the generic parameter is intended to be "TSelf" of a derived class, in reality T is unconstrained and essentially arbitrary. This opportunizes two new classes of bug: if base class specification Y : AbstractBase<...> mistakenly references a different AbstractBase‑der­ived class X, the values of the "abstract static property" for X and Y will be incorrectly conflated -- and/or -- any usage call-site AbstractBase<T>.AbstractStaticProp with a mistaken type argument (such as DateTime) will spontaneously--and silently--demand a fresh new "instance" of the static property.
The last bullet point can be somewhat mitigated by adding a constraint on the generic base:
/// v---- constraint added
abstract class AbstractBase<TSelf> where TSelf : AbstractBase<TSelf>
{
public static String AbstractStaticProp { get; set; }
};
This eliminates the possibility of class Derived2 : AbstractBase<DateTime> { /*...*/ }, but not the error class Derived2 : AbstractBase<Derived1> { /*...*/ }. This is due to a recurring conundrum that foils all attempts at constraining a generic type to some exact branch of the type-inheritance hierarchy:
The "TSelf problem"
Generic constraints are always at the mercy of the type arguments that are supplied, which seems to entail that it's impossible to construct a generic constraint that guarantees that some particular TArg within its scope refers to a type that is derived from itself, that is, the immediate type being defined.
The error in this case is an example of this; while the constraint on AbstractBase<TSelf> rules out incompatible disjoint types, it can't rule out the unintended usage Derived2 : AbstractBase​<Derived1>. As far as AbstractBase is concerned, the supplied type argument Derived1 satisfies its constraint just fine, regardless of which of its subtypes is deriving itself (im-)properly. I've tried everything, for years, to solve TSelf; if anyone knows a trick I've missed, please let me know!
Anyway, there are still a couple other points to mention. For example, unless you can immediately spot the problem in the following code, you'll have to agree that it's a bit dangerous:
public static new String AbstractStaticProp
{
get => AbstractBase<Derived1>.AbstractStaticProp;
set => AbstractBase<Derived2>.AbstractStaticProp = value;
}
Ideally, you want to get the compiler to do what it's meant to, namely, understand that all AbstractStaticProp property instances are related and thus somehow enforce their unification. Since that's not possible for static methods, the only remaining option is to eliminate the extra versions, effectively reducing the problem to the unification of just one, a vacuous operation, obviously.
It turns out that the original code is being too elaborate; the generic-base class approach wants to collapse on the simpler solution all by itself without having to explicitly request it, such as those new-marked properties seem to be doing with the qualification in AbstractBase<Derived1>.​AbstractStaticProp".
You can already refer to each respective independent copy of the static property by qualifying with the derived class name instead (in fact, #Gusman's test harness shows this), so the end result is that the property declarations in the derived class aren't necessary at all. Without further ado, here is the complete simplified version:
abstract class AbstractBase { };
abstract class AbstractBase<TSelf> : AbstractBase
where TSelf : AbstractBase<TSelf>
{
public static String AbstractStaticProp { get; set; }
};
class Derived1 : AbstractBase<Derived1> { };
class Derived2 : AbstractBase<Derived2> { };
This works identically to the code at the top. The test harness gives the same results as before.
static void Test()
{
Derived1.AbstractStaticProp = "I am Derived1";
Derived2.AbstractStaticProp = "I am Derived2";
Debug.Print(Derived1.AbstractStaticProp); // --> I am Derived1
Debug.Print(Derived2.AbstractStaticProp); // --> I am Derived2
}
What you're trying to do is impossible, as others have mentioned.
I'd try something like this
public abstract class ProviderConfiguration : ConfigurationSection
{
public string ConfigurationSectionName { get; set; }
public static ProviderConfiguration Provider { get; set; }
public static Configuration Current
{
get { return (Configuration)ConfigurationManager.GetSection(Provider.ConfigurationSectionName); }
}
}
Then in practice:
public void DoStuff()
{
var provider = new DerivedProviderConfiguration();
ProviderConfiguration.Provider = provider;
}

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
{
}

Categories