views:

88

answers:

4

I am trying to do something like this in C#

public class ParentClass {
  public static ParentClass GetSomething()
  {
    var thing = new // ?????
    return thing;
  }
}

public class ChildClass : ParentClass {
}

And then I want to be able to call the static method on the child class like so:

ChildClass blah = ChildClass.GetSomething();

e.g. When calling the static method on the child class I want to instantiate an instance of the child class. But I just want the static method defined on the parent. Is this at all possible? I'd be happy even with:

ChildClass blah = (ChildClass) ChildClass.GetSomething();

Thanks!

+3  A: 

C# doesn't let you override static methods.

There's nothing stopping you, though, from redefining a new static method on ChildClass that hides the ParentClass method. Would doing that help?

Tinister
+4  A: 

You cannot 'override' static methods. But you can use generics to tell the ParentClass which derived class you actually means. It's somewhat ugly but it works:

class ParentClass<T> where T : ParentClass<T>, new()
{
    public static T GetSomething()
    {
        T thing = new T();
        return thing;
    }
}

class ChildClass : ParentClass<ChildClass>
{
}

Test:

ChildClass x = ChildClass.GetSomething(); // works
dtb
Thanks for the answer. Looks like that's the syntax to do exactly what I asked for in my demo code... I'll integrate it in the actual codebase and let you know how it works out :)
vitch
In fact, what is the difference between defining the <T> at the class level vs the method level? That seems to be the difference between the two solutions...
vitch
This solution works the following way: in `ChildClass.GetSomething();` compiler can see that ChildClass is inherited from ParentClass with parameter T = ChildClass. This value of T is then used in declaration of return type of `GetSomething()` method. Thus you don't need to specify return type anywhere else. Pros: Simpler syntax of calling your method. Cons: More complicated code with less flexibility.
Roman Boiko
The difference is that T from BaseClass and T from method return type must be the same in this example.
Roman Boiko
Thanks for the answer... I saw the same thing explained here: http://stackoverflow.com/questions/1853414/generic-repository-irepositoryt-or-irepository - either the type of T is set for the entire class or on a per method basis...
vitch
Marked this as the answer although all of the answers were very good and useful! This one was just the first and I'm new to stack overflow and not sure on the etiquette for selecting the correct answer when you have multiple good ones...
vitch
+5  A: 

This smells awful, but you could do this:

public class ParentClass {
    public static T GetSomething<T>() where T : ParentClass, new() {
        return new T();
    }
}

Usage:

ParentClass parent = ParentClass.GetSomething<ParentClass>();
ChildClass child = ChildClass.GetSomething<ChildClass>();

This is legit too:

ParentClass parent = ChildClass.GetSomething<ParentClass>();

which contributes to the smelliness of this (yes it just compiles to ParentClass parent = ParentClass.GetSomething<ParentClass>() but it still smells).

Jason
The only smelly bit is calling the parameterless constructor, IMO - and it's possible that there are ways around that in the real code. The basic premise of making it a generic method is sound :)
Jon Skeet
Thanks for the answer. I felt it lay somewhere in generics but I'm pretty new to C# and have just been picking it up as I go along... Can anyone recommend a good introduction to generics? And one for general C# best practices too in fact!I'll try applying these solutions to my actual class structure and see what works out best (obviously the above was a total simplification). Thanks again!
vitch
@vitch: Jon Skeet's book has a very nice chapter on generics (and if you're far along in your C# development, I recommend highly). As for "C# best practices" I think that Effective C# and More Effective C# (Bill Wagner) are good here as well as The Framework Design Guidelines (Microsoft). (Jon's book is good in this regard too, but not as explicitly as the aforementioned texts.)
Jason
Thanks Jason, I'll see if I can grab hold of them... I read the MSDN introduction to generics and it looks like they are actually pretty simple, it's just a case of learning a little bit of syntax :)
vitch
@vitch: Yes, the syntax is quite simple (we are not talking C++ style templates here which are a completely different beast altogether). The art is in learning when to use generics. :-)
Jason
+4  A: 

This line:

ChildClass blah = ChildClass.GetSomething();

is compiled to exactly the same IL as this line:

ChildClass blah = ParentClass.GetSomething();

(when ChildClass doesn't declare its own GetSomething method).

I would prefer:

ChildClass blah = ParentClass.GetSomething<ChildClass>();

It's like your casting version, but with angle brackets and the type name coming after instead of before the method name :) (Basically Jason's suggestion, now I've seen it!)

However, this is now somewhat independent of ParentClass - you can define it anywhere that's useful:

public static class FactoryUtil
{
    public static T CreateInstance<T>() where T : ParentClass
    {
        ...
    }
}

... or you could provide a factory as a dependency where you need it, making things more testable, potentially...

Jon Skeet
Thanks for the answers and clarification... I'll also have a think about the factory approach, I need to now look back into my actual code base and try to figure out the best way to apply this new found knowledge to it!
vitch