views:

217

answers:

9

I want to do the following

public abstract class MyAbstractClass
{
    public static abstract int MagicId
    {
        get;
    }

    public static void DoSomeMagic()
    {
        // Need to get the MagicId value defined in the concrete implementation
    }
}

public class MyConcreteClass : MyAbstractClass
{
    public static override int MagicId
    {
        get { return 123; }
    }
}

However I can't because you can't have static abstract members.

I understand why I can't do this - any recommendations for a design that will achieve much the same result?

(For clarity - what I am trying to do is provide a library with an abstract base class but the concrete versions MUST implement a few properties/methods themselves and yes, there are good reasons for keeping it static.)

+5  A: 

You fundamentally can't make DoSomeMagic() work with the current design. A call to MyConcreteClass.DoSomeMagic in source code will be translated into MyAbstractClasss.DoSomeMagic in the IL. The fact that it was originally called using MyConcreteClass is lost.

You might consider having a parallel class hierarchy which has the same methods but virtual - then associate each instance of the original class with an instance of the class containing the previously-static members... and there should probably only be one instance of each of those.

Jon Skeet
Yes I understand the why I can't do the above - my question is whats the correct design.
Ryan
@Ryan: That's why I included the second paragraph as well :)
Jon Skeet
A: 

Not a huge fan of this option but...

You could declare the property static, not abstract, virtual and throw a NotImplementedException which returns an error message that the method has to be overridden in a derived class.

You move the error from compile time to run time though which is kinda ugly.

JoshReedSchramm
You can't override static members.
zneak
Bah oops. I'd downvote myself if i could
JoshReedSchramm
+2  A: 

Your best option is to use an interface with MagicId only using a setter

public interface IMagic
{
    int MagicId { get; }
}

By the nature of Static meaning there can only be one (yes like Highlander) you can't override them.

Using an interface assumes your client will implement the contract. If they want to have an instance for each or return the value of a Static variable it is up to them.

The good reason for keeping things static would also mean you do NOT need to have it overridden in the child class.

David Basarab
+1 for Highlander remark
statenjason
How does using Interfaces get me any further than non-static abstract? In fact its worse as compiler doesn't force concrete class to implement interface.http://stackoverflow.com/questions/510341/force-subclasses-of-an-interface-to-implement-tostring-c
Ryan
A: 

Languages that implement inheritance of static members do it through metaclasses (that is, classes are also objects, and these objects have a metaclass, and static inheritance exists through it). You can vaguely transpose that to the factory pattern: one class has the magic member and can create objects of the second class.

That, or use reflection. But you can't ensure at compile-time that a derived class implements statically a certain property.

zneak
+3  A: 

Would the Singleton pattern work perhaps? A link to the MSDN article describing how to implement a singleton in C#:

http://msdn.microsoft.com/en-us/library/ff650316.aspx

In your particular example, the Singelton instance could extend an abstract base class with your MagicId in it.

Just a thought :)

Allen E. Scharfenberg
A: 

Why not just make it a non-static member?

bitbonk
Which member - or all of them?
Ryan
+2  A: 

I would question that there are "good reasons" for making the abstract members static.

If your thinking is that these members might reflect some property of the derived class itself rather than a given instance, this does not necessarily mean the members should be static.

Consider the IList.IsFixedSize property. This is really a property of the kind of IList, not any particular instance (i.e., any T[] is going to be fixed size; it will not vary from one T[] to another). But still it should be an instance member. Why? Because since multiple types may implement IList, it will vary from one IList to another.

Consider some code that takes any MyAbstractClass (from your example). If this code is designed properly, in most cases, it should not care which derived class it is actually dealing with. What matters is whatever MyAbstractClass exposes. If you make some abstract members static, basically the only way to access them would be like this:

int magicId;
if (concreteObject is MyConcreteClass) {
    magicId = MyConcreteClass.MagicId;
} else if (concreteObject is MyOtherConcreteClass) {
    magicId = MyOtherConcreteClass.MagicId;
}

Why such a mess? This is much better, right?

int magicId = concreteObject.MagicId;

But perhaps you have other good reasons that haven't occurred to me.

Dan Tao
A: 

Sounds like a Monostate, perhaps? http://c2.com/cgi/wiki?MonostatePattern

Wayne
A: 

The provider pattern, used by the ASP.NET membership provider, for example, might be what you're looking for.

You cannot have polymorphic behavior on static members, so you'll have a static class whose members delegate to an interface (or abstract class) field that will encapsulate the polymorphic behaviors.

Jordão