Click here to Skip to main content
15,891,136 members
Please Sign up or sign in to vote.
2.75/5 (4 votes)
See more:
Hi Folks,

I'm looking for a more elegant way to retrieve the type information in a static constructor.

Here is a sample of the problem:
C#
public class Base
{
    private static Type _typeInfo;
    public static string TypeName;
    static Base()
    {
        //Type info goes here. Not Base class type info but from any derived class.
        _typeInfo = ????; 
        TypeName = _typeInfo.Name;
    }
}

public class Derived : Base
{
}

//I want those asserts to work.
Assert.AreEqual("Base", Base.TypeName);
Assert.AreEqual("Derived", Derived.TypeName);


I don't need (or even want) those classes to be instanciated. I just need their static properties and methods.

There is a solution using generics:
C#
public class Base<TSource> where TSource : Base<TSource>
{
    private static Type _typeInfo;
    public static string TypeName;
    static Base()
    {
        _typeInfo = typeof(TSource);
        TypeName = _typeInfo.Name;
    }

    public static string CommonInfo = "PresentInAllClasses";
}

public class Derived1<TSource> : Base<TSource> where TSource : Derived1<TSource>
{
    public static string DerivedInfo = "OnlyOnDerivedClasses";
}

public class Base : Base<Base> { }

public class Derived1 : Derived1<Derived1> { }

public class Derived2 : Derived1<Derived2>
{
    public static string FinalInfo = "OnlyInFinalClass";
}

//Those asserts works fine.
Assert.AreEqual("Base", Base.TypeName);
Assert.AreEqual("Derived1", Derived1.TypeName);
Assert.AreEqual("Derived2", Derived2.TypeName);
Assert.AreEqual("PresentInAllClasses", Base.CommonInfo);
Assert.AreEqual("PresentInAllClasses", Derived1.CommonInfo);
Assert.AreEqual("PresentInAllClasses", Derived2.CommonInfo);
Assert.AreEqual("OnlyOnDerivedClasses", Derived1.DerivedInfo);
Assert.AreEqual("OnlyOnDerivedClasses", Derived2.DerievedInfo);
Assert.AreEqual("OnlyInFinalClass", Derived2.FinalInfo);


But I don’t see it as very elegant solution 'cause:
1 - I have to write the name of the target classes twice in it's declaration. (ugly)
2 - I have to propagate the generic declaration for any subclass I want to extend. (very ugly)
3 - I have to declare the target class as a generic of itself. (Very, very ugly)

Any ideas?

Thanks
Andre Vianna
Posted
Updated 31-Mar-10 10:09am
v5

What you're asking doesn't make sense. Static members deal with types not objects and as you've found out polymorphism only works with instances of objects.

Consider this: Base.TypeName can only hold one string value per AppDomain. What value would it hold if you had the Base class and a derived class? It can't change value depending on if it was accessed through Base.TypeName or Derived.TypeName.

Nick
 
Share this answer
 
Hi,
It seems like its impossible what you are trying to achieve(or at least useless).
Static constructor of a class is called at most one time during program life and it is not inherited. So even if you set correct type it will be set only for the Base class and you will have to set it again in derived classes.
Maybe you could make use of typeof().
for e.g.:

class Utils{
public static string GiveMeName(Type t){
    //add whatever info more you need here}
}

Utils.GiveMeName(typeof(Base));


Well.. its not so pretty as you might want but it does the job :P
..or you could use generics
..or rewrite same code in static constructors for all classes
 
Share this answer
 
I can not figure out when anyone would ever need what you're trying to achieve, but that's beside the point :)

As the static constructor of Base will not be called as a chained call graph, such in the case of the non static constructor, but rather on first use of a instance of Base is created or when a static member is accessed you can't get to the derived type as static methods are inherited.

If you really do need this information I'd solve it with static properties on each class:

C#
public class Base
{
    public static string TypeName
    {
        get { return typeof(Base).Name; }
    }
}

public class Derived : Base
{
    public static string TypeName
    {
        get { return typeof(Derived).Name; }
    }
}


At least this way the uglyness (i.e. repeating code) will be contained and hidden away in the classes rather than forcing the user of your classes to specify redundant type arguments to let generics figure the type out.

Hope this helps.
 
Share this answer
 

Thank you for the question, it was inspirational.

I'm pretty sure that the answer is no. You are trying to do something that is not allowed. This is something that I really wanted to do but failed.
However now thanks to your question I have became inspired to create a work around that I can live with.

Consider the following simple property for the class ParametricShapeBase

C#
static Type ClassType
  {
      get { return typeof(ParametricShapeBase); }
  }


That is a very simple property that you can add to your class that will allow you to do what you want.

The question you might be wondering about is why I find this so interesting. If you work with WPF a lot you will end up using dependency properties. Their declarations contain the class name.
For example

public static DependencyProperty ValueProperty  
 = DependencyProperty.Register("Value", typeof(double), typeof(MathParameterAdaptor));


This is all very nice but it makes copying and pasting them between classes a pain. If one uses the ClassType property the copy paste situation is solved.

This solution is far from ideal but I find it only mildly lame.
Thanks
Ken
 
Share this answer
 
v5
As well as being ugly and changing the symantics of your base class, the I *think* the generic solution is not thread safe.


Along with others I'm not sure why you want to achieve this there is a bad code-smell to it that I can't quite pinpoint. IMO if you have one static method in a class, then the everything in the class should be declared static as well as the class. Obviously this would wreck the iheritance hierarchy.

Anyhoo this is a cleaner posssible solution, but requires more diligance from the coder:

C#
class Foo
{
    public static Type Type
    {
        get { return typeof(Foo); }
    }
}

class Bar : Foo
{
    public static Type Type
    {
        get { return typeof(Bar); }
    }
}
 
Share this answer
 
You can apply the singleton pattern to allow only a single instance of the class:

C#
public sealed class Singleton
{
    private static Singleton _instance;

    public static Singleton Instance
    {
        get
        {
            if (_instance == null)
                _instance = new Singleton();
            return _instance;
        }
    }
    private Singleton()
    {
    }
}


And this would allow you to use as many instance methods as you need.

If you want to check dynamically for type information (i.e. assembly metadata) you can dig into reflection (check this sample).

The following code prints out the base name of a specific class:

C#
Type t = typeof(System.Int32);
Console.WriteLine(t.BaseType.FullName);
 
Share this answer
 
Hi KenJohnson,

First of all thanks for really try to undertand the problem. It is sad to see that most of the people don't even read the question to the end or do not spend a second to try to view the larger picture.

For those short minded a few words:
1 - By using the derived class as a generic of the base class you can actually simulate the chaining of the instance constructors. Look for the term SIMULATE! I realy do not need the constructor of the base class (Base) to be called. Just the one from Base class which is not the same class as Base. And I just need it to be called once because (as I pointed cleared in the question) I will ONLY USE the static propereties and methods of the class.

2 - Singleton or Sealed classes do not solve the problem. I want to reuse the class and be able to inherit from it.

3 - I'm already using reflection. PLEASE read the code!!!

4 - Yes!! Type inheritance is possible! Not only instanciated objects. I proved that in the sample I put in the end of the question. It's works perfectly.

5 - If I could write the name of the class in the static constructors I would not have all that problem, would I? Come on! You are smarter than that.

Now...
Imagine that the base class is declared in a Assembly and the derived class is writen in other.

And jus to blow out your minds, I will hust give a taste of this potential (ATTENTION: I'M NOT GIVEN ALL THE CODE THAT MAKES THAT IMPLEMENTATION POSSIBLE...)

C#
[Flags]
enum Animals
{
    Squid = 0,
    Lizard = 1,
    Giraffe = 2,
    Dog = 4,
}

class Animal : CategorizedEnum<Animal, Animals>
{
    public class Invertebrate
    {
        public Animals Squid;
    }
    public class Vertebrate
    {
        public class Reptile
        {
            public Animals Lizard;
        }
        public class Mamal
        {
            public Animals Giraffe;
            public Animals Dog;
        }
    }
}

var myAnimal = Animal.Vertebrate.Mamal.Giraffe;
Assert.AreEqual(Animals.Giraffe, myAnimal);
Assert.AreEqual(Animals.Giraffe | Animals.Dog, Animal.Vertebrate.Mamal);
Assert.AreEqual("Animal_Vertebrate_Mamal_Giraffe_Name", Animal.Vertebrate.Mamal.Giraffe.ResourceKey("Name"));
Assert.IsNotNull(Animal.Vertebrate.Mamal.Giraffe.Resource("Icon"));


That code is just an extract of the full implementation, but it WORKS!

It uses a lot of reflection, abstracts and operators overriding but the final result very good.
I just want make it more elegant.

Regards
Andre
 
Share this answer
 
v4

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900