views:

114

answers:

4

Ok... in C++ you can new up a subclass from a static method in the base class with 'new this()' because in a static method, 'this' refers to the class, not the instance. That was a pretty damn cool find when I first found it and I've used it often.

However, in C# that doesn't work. Damn!

So... anyone know how I can 'new' up a subclass from within a static base class method?

Something like this...

public class MyBaseClass{

    string name;

    public static Object GimmeOne(string name){

     // What would I replace 'this' with in C#?
        return new this(name); 

    }

    public MyBaseClass(string name){
        this.name = name;
    }

}

// No need to write redundant constructors
   public class SubClass1 : MyBaseClass{ }
   public class SubClass2 : MyBaseClass{ }
   public class SubClass3 : MyBaseClass{ }

SubClass1 foo = SubClass1.GimmeOne("I am Foo");

And yes I know I can (and normally would) just use the constructors directly, but we have a specific need to call a shared member on the base class so that's why I'm asking. Again, C++ lets me do this. Hoping C# does too.

So... any takers?

M

A: 

Sorry, you can't do this. C# is morally opposed to static method inheritance. That GimmeOne method will never have any type other than MyBaseClass, and calling it from SubClass1 doesn't matter- it's still "really" a MyBaseClass call. The Reflection libraries could do this construction, but you'd never get anything other than a MyBaseClass out of it.

If you're calling a static method, presumably you know which subclass you're calling it from. Create a different factory method for each subclass. If you're actually trying to do this by instance, you should probably use a non-static virtual factory method (which will automatically call the most derived form of the function, which is probably what you want) instead.

Kistaro Windrider
A: 

Try factory method pattern.

Sidharth Panwar
I understand the factory method pattern but that doesn't necessarily achieve what I want. Can you be more specific? A link or reference perhaps?
MarqueIV
The one size fit all won't work in C# because the this implementation doesn't work that way. Best bet is Generics + Factory. You can take a hint from @Steve's sample.
Sidharth Panwar
+2  A: 

C# doesn't have any exact equivalent to that. However, you could potentially get around this by using generic type constraints like this:

public class MyBaseClass
{
    public string Name { get; private set; }

    public static T GimmeOne<T>(string name) where T : MyBaseClass, new()
    {
        return new T() { Name = name };
    }

    protected MyBaseClass()
    {
    }

    protected MyBaseClass(string name)
    {
        this.Name = name;
    }
}

The new() constraint says there is a parameterless constructor - which your didn't but we make it private to hide that from consumers. Then it could be invoked like this:

var foo = SubClass1.GimmeOne<SubClass1>("I am Foo");
Steve Michelotti
Man... I'm kicking myself! I didn't even think Generics, and I use them all the time! It's the da*n hat-switching between C# and C++ (and Objective-C[++] for that matter!) Quick question though... Instead of the 'new()' constraint and 'return new T(){Name=name};' couldn't you instead make the constraint to be something of type 'MyBaseClass', then just call 'return new T(name);'? That way you still have full use of a proper constructor and not just simple assignment. BTW, in your code, why do you still need 'protected MyBaseClass(string name)' let alone why did you change it from public?
MarqueIV
I may have just remembered something... don't you HAVE to have the 'new()' constructor to 'new' something up? I take it there's no way to have a 'new(string)' constraint? ...or is there?
MarqueIV
Correct - you HAVE to hve the new() constraint in order to "new" something.
Steve Michelotti
The second constructor could still be public - yes, either way is fine. I made it protected because it appeared that the intent of your code was to have consumers create the object with the factory method rather than the constructor. Plus, if you ever change MyBaseClass to be abstract, then best practices state that the constructor should be protected and not public (since a consumer can't instantiate an abstract class's constructor directly anyway).
Steve Michelotti
Well we only had that base class constructor because we were intending to 'pick it up' in the subclasses like we can in C++, but since we can't, your code works fine, and we can most likely just delete it. Actually, we'd probably change it to be 'protected void Init(string name)' and call that rather than constructor assignment so we can a) do more than just simple assignment, and b) allow subclasses to override it if needed. Either way, I've accepted your answer and voted it up too. Damn good stuff, my friend! Very!
MarqueIV
+1  A: 

Am I missing something here? Which compiler are you using to compile your c++ code? For the life of my I can't figure out how your c++ will compile. As far as I know there is no such thing as a "this" constructor in c++. I even attempted to compile your code and was given a syntax error. From what you've described, it doesn't sound like c++ but actually Java.

If that's the case then I can sleep easy at night again knowing that all is right in the world!

Bob9630
My bad, Bob! I just went back and looked. It's actually Objective-C I was referring to, not C++. Since I actually use Objective-C++, I tend to blend the two of them together when talking about it. Here's the link to that one... http://stackoverflow.com/questions/3210101/get-class-type-in-shared-objective-c-method
MarqueIV
Voted you up because of your sleepless nights! (and for calling out my error!)
MarqueIV