4

From an instance, I might do this.

 var obj= Activator.CreateInstance(GetType());

Not sure how to get typeof of the inherited class in a static base method though.

Is this the best way forward?

 public static Method<T>() where T : SomeBase, new()
sgtz
  • 8,849
  • 9
  • 51
  • 91

3 Answers3

4

You could make the base class generic and close the generic in the derived class.

public abstract class CreatorOf<T> where T : CreatorOf<T>
{
    public static T Create()
    {
        return (T)Activator.CreateInstance(typeof(T));
    }
}

public class Inheritor : CreatorOf<Inheritor>
{
    public Inheritor()
    {

    }
}


public class Client
{

    public Client()
    {
        var obj = Inheritor.Create();
    }
}

There are some who consider this to be an "anti-pattern", but I believe there are circumstances where it is an acceptable approach.

Community
  • 1
  • 1
Steve Rowbotham
  • 2,868
  • 17
  • 18
  • This is the [CRTP](http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern). I am not sure whether it works in C#. If it does work (google had some article that said it wouldn't, but [this SO question seems to say otherwise](http://stackoverflow.com/questions/1327568/curiously-recurring-template-pattern-and-generics-constraints-c)), then it isn't the anti-pattern you think it is, and could be a solution here if abstract factory doesn't seem attractive enough to the OP :) – Merlyn Morgan-Graham Nov 01 '11 at 11:16
  • @MerlynMorgan-Graham To be clear, I don't think it's an "anti-pattern" (a term that's bandied about too frequently IMHO). I just wanted to alert the OP to other opinions so that they can decide for themselves whether it's appropriate for their situation. It works fine in C# BTW. – Steve Rowbotham Nov 01 '11 at 11:26
  • +1 BTW. I think the question you linked doesn't match this pattern because in their example the generic parameter isn't the same as the derived type. In your case it is the same, hence being the CRTP. – Merlyn Morgan-Graham Nov 01 '11 at 17:35
  • @MerlynMorgan-Graham Yes, possibly, although some of the posters seemed to be objecting in principle to a derived class closing the generic base class. However, it's not an opinion I hold so it's difficult for me to say TBH. – Steve Rowbotham Nov 01 '11 at 17:54
3

Maybe you should better tryto use abstract factory pattern? http://en.wikipedia.org/wiki/Abstract_factory_pattern

Lonli-Lokli
  • 3,357
  • 1
  • 24
  • 40
  • maybe. Wanted a self-discovery way of doing it though. static Method() seems to be almost the same thing as an abstract factory minus the asthetic of having an abstract factory. Thanks for pointing this out though. Made me think. – sgtz Nov 01 '11 at 10:15
  • @sgtz There was a question about Abstract Factory in C# recently which I gave an answer to which might be helpful http://stackoverflow.com/questions/7945541/use-of-factory-pattern/7945887#7945887 – Steve Rowbotham Nov 01 '11 at 11:04
2

There is no such thing as a derived static method. So there is no way to create a static factory method that returns a different type depending on which derived class you call it on.

As Lonli-Lokli suggested, you should use the Abstract Factory design pattern.

public interface ISomething
{
    void DoSomething();
}

public class SomeClass : ISomething
{
    public virtual void DoSomething() { Console.WriteLine("SomeClass"); }
}

public class SomeDerivedClass : SomeClass
{
    private int parameter;

    public SomeDerivedClass(int parameter)
    {
        this.parameter = parameter;
    }

    public virtual void DoSomething()
    {
        Console.WriteLine("SomeDerivedClass - {0}", parameter);
        base.DoSomething();
    }
}

public interface IFactory
{
    public ISomething Create();
}

public class SomeClassFactory : IFactory
{
    public ISomething Create() { return new SomeClass(); }
}

public class SomeDerivedClassFactory : IFactory
{
    public ISomething Create() { return new SomeDerivedClass(SomeParam); }

    public int SomeParam { get; set; }
}

Pros of Abstract Factory vs static Factory methods:

  • It is much more flexible, allowing a new implementation of your factory logic (which can be as complicated as you want) for every implementor of the abstract factory. You could have more than one factory per class, if you wanted.
  • Since you aren't calling a static method, it is much easier to replace at runtime. This is quite useful for injecting mocks in unit tests.

The pros are huge. Abstract Factories are superior to static factory methods in every way, even if you could get static methods to work the way you want them to.

Cons of Abstract Factory vs static Factory methods:

  • Users of the abstract factory must have a factory instance to create your derived types.
  • You have to write a new abstract factory implementation for each derived class.

The cons are very marginal.

It is extremely easy for a user to instantiate a factory to create a single object:

MyClass myClass = new MyClassFactory().Create();

As for code duplication in the factory implementation: Saving the implementer a tiny bit of typing is pointless. It is a goal in programming to write code that can be read, understood, and easily modified. There is no programming goal to save paper or keystrokes :)

Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183
  • I wouldn't use a generic interface for implementing Abstract Factory because the factory and its product are meant to be abstract so the type parameterization isn't useful. If the client of the factory only depends on non-generic IFactory and IProduct abstractions then it is completely decoupled from the concrete types of both. Making them generic either forces the client to be generic or the type has to be closed which defeats the abstraction. Consider DoSomething(IFactory factory) versus DoSomething(IFactory factory). – Steve Rowbotham Nov 01 '11 at 11:22
  • @Steve: I just threw that in there at the last minute and didn't think about it very hard. Now that I think about it, I don't create abstract factories that way. It seemed a bit strange when I did it :) Fixing... – Merlyn Morgan-Graham Nov 01 '11 at 17:26
  • 1
    Yes, since the type parameter in generic factory interface would only appear as a return type then you could use the covariance to pass, say, an IFactory to a method expecting IFactory but I don't think that you gain anything from the interface being generic and so I still think that your final version is better. :) – Steve Rowbotham Nov 01 '11 at 18:01
  • @Steve: Yep. I can't think of any interesting scenarios that could use the `IFactory` in a generic manner. The thing it buys you is that you only have to define the factory interface once. But the false flexibility (you can't really use it in a flexible manner in base classes) makes it difficult for users to understand the correct way to use the factory (as proven by my broken first revision). Rewriting the interface each time is much safer, and costs very little typing - the same trade-off I recommended in my answer for using the abstract factory to begin with. – Merlyn Morgan-Graham Nov 01 '11 at 18:21