-1

Here's the specific situation: I have a base abstract class Effect that contains some behavior that is shared amongst all types of effects. Then I have several derived class that inherit from Effect.

I want to have something like

public static virtual Effect CreateEffect(GameObject obj)
{
    if (!IsCreateable()) {
        return;
    }

    //Otherwise create the effect
}

public static virtual bool IsCreateable()
{
    //Some generic logic common amongst all Effects
}

And then in derived classes some of them require some extra custom logic

public static override bool IsCreateable()
{
     if (custom logic) {
         return false;
     }

     return base.IsCreateable()
}

Obviously this isn't possible because c# doesn't support static virtual function. I would like a way to share this static code amongst the classes without having to rewrite code. I can't have it as an instance method because in this case the code is being used to decide whether to create an instance in the first place.

In general, how do you have functions that is type-level (doesn't require an instance) with default behavior that can be overridden or modified in C#?

Assume this behavior is something separate from the constructor (for example in Unity3D you can't use a constructor to instantiate Monobehaviors).

StackedAE
  • 7
  • 1
  • 5
  • As with most programming problems: just add an indirection level. Implement the `IsCreatable` method on factory objects rather than on the actual object you want to create – Kevin Gosse Jun 30 '17 at 06:37
  • What do you mean by implementing IsCreatable on factory objects? Can you elaborate a bit? – StackedAE Jun 30 '17 at 06:39
  • How is your question any different from all the other "I want to override static members" questions that already exist on Stack Overflow. I don't see anything new here...there are plenty of questions with answers already that address this type of scenario. If you want actual override-able class-level (static) members, you need a different language. If you want this sort of thing in C#, you're stuck with one of the work-arounds that have already been well-documented in other questions. – Peter Duniho Jun 30 '17 at 06:41
  • 1
    Define a `BaseEffectFactory` with `IsCreatable` and `CreateEffect` methods. Write child classes as needed, inheriting from it (for instance, `CustomEffectFactory` will create `CustomEffect` instances). Basically, separate the "create effect" logic from the actual effect – Kevin Gosse Jun 30 '17 at 06:41
  • https://en.wikipedia.org/wiki/Factory_method_pattern – Kevin Gosse Jun 30 '17 at 06:43
  • possible duplicate of https://stackoverflow.com/questions/29146979/how-to-override-static-factory-like-method-in-subclasses – Peter Duniho Jun 30 '17 at 06:47
  • possible duplicate of https://stackoverflow.com/questions/2074454/override-a-static-method – Peter Duniho Jun 30 '17 at 06:47
  • possible duplicate of https://stackoverflow.com/questions/25490269/overridable-methods-cannot-be-static-how-else-can-i-do-what-im-trying-to-do – Peter Duniho Jun 30 '17 at 06:47
  • possible duplicate of https://stackoverflow.com/questions/30127299/workaround-for-static-member-inheritance-in-c-sharp – Peter Duniho Jun 30 '17 at 06:48
  • possible duplicate of https://stackoverflow.com/questions/14828271/can-a-static-method-be-overridden-in-c – Peter Duniho Jun 30 '17 at 06:48
  • Broadly, there are at least three different options described in these many duplicates: hide base class members (works "fine" if you are always using the derived class to call members); use metadata (i.e. attributes) to create a data-driven implementation; or just give up and make a separate factory class hierarchy so that you can use conventional virtual member features. That's not to say these are the only three ways to approach the problem; just that they are common ways documented on Stack Overflow. – Peter Duniho Jun 30 '17 at 06:50
  • Thanks Peter, those links along with your response are actually very helpful. – StackedAE Jun 30 '17 at 06:56
  • So if I'm understanding the factory method correctly, for each derived effect class I'd also need to make a derived factory class with a singleton object? This seems a bit inconvenient and BRITTLE. – StackedAE Jun 30 '17 at 07:04
  • Tip: use `@` to notify a person to whom your comment is directed. As for your question about "brittle", it depends on how you implement it. But I don't see it as much more brittle than virtual methods in the original classes would be. You can still forget to override and get default behavior instead of what you want. One pattern is to declare your derived factory classes as nested inside the class they go with (they will have access to `private` constructors there), so at least the factory classes are closely tied to the classes they create. – Peter Duniho Jun 30 '17 at 07:41

1 Answers1

0

You could use the new keyword for this. It is not exactly as clean as overriding but gets the job done:

public class Effect
{
    public static Effect CreateEffect()
    {
        if (!IsCreateable())
        {
            return null;
        }

        return new Effect();
        //Otherwise create the effect
    }

    public static bool IsCreateable()
    {
        //Some generic logic common amongst all Effects
        return true;
    }
}

public class Effect2 : Effect
{
    public new static Effect2 CreateEffect()
    {
        if (!IsCreateable())
        {
            return null;
        }

        return new Effect2();
        //Otherwise create the effect
    }

    public new static bool IsCreateable()
    {
        //Some generic logic common amongst all Effects
        return true;
    }
}
Romano Zumbé
  • 7,893
  • 4
  • 33
  • 55
  • In this case you have to copy and paste the CreateEffect method into every derived Effect class, even though it is identical in all of them, right? – StackedAE Jun 30 '17 at 06:40
  • No, if it is identical in all classes just don't create a new static method and use the implementation from the base class. Only override the functions that change. You can override it only in those classes that will have a different mechanism for `IsCreateable` others will use the base classes method. – Romano Zumbé Jun 30 '17 at 06:43
  • In this case, Effect2.CreateEffect would create a new Effect(), when really I need it to create a new Effect2 (technically I need it to do AddComponent instead of new). – StackedAE Jun 30 '17 at 07:02