3

I've created an abstract class, lets call it FooBarizable, that is the parent of 2 clases(more in the practice), Foo and Bar. Now, I have a FooBarizableManager that manages Foo and Bar classes, depending on his type. And from this FroobarizableManager, I want to call getFooBarizables(). Let's see the structure:

FooBarizable.cs:

public abstract class FooBarizable{

    public string Name { get; set; }
    public static IEnumerable<FooBarizable> GetFooBars(){
        throw new NotImplementedException();
    }
}

Foo.cs:

public class Foo : FooBarizable{

    public static IEnumerable<FooBarizable> GetFooBars(){
        return API.getFoos();
    }
}

Bar.cs:

public class Bar : FooBarizable{

    public static IEnumerable<FooBarizable> GetFooBars(){
        return API.getBars();
    }
}

FooBarizableManager.cs:

public class FooBarizableManager {

    private Type type;
    public FooBarizableManager(Type _t){
        this.type = _t;
    }

    public void showFooBarizables(){

        MethodInfo method = type.GetMethod("GetFooBars");

        IEnumerable<FooBarizable> FooBars = (IEnumerable<FooBarizable>)method.invoke(null, null);

        show(FooBars);
    }

    ...

}

So, my problem is that I want to get the object collection from the manager, using the type, but enforce child classes to implement getFooBars() method.

Problems I've faced:

  • .Net does not allow to define static abstract methods, so I cannot create public static abstract IEnumerable<FooBarizable> GetFooBars() and enforce child class to implement it.

  • The way that is implemented does not enforce the implementation of the method in child classes, but I try to at least throw a NotImplementedException. The problem is that when I call MethodInfo method = type.GetMethod("GetFooBars"); in the manager, if the subclase does not implements the method, method is null, and NullPointerExceptionis called instead.

  • I've tried to create an instance method instead of static a static one, it solves the enforce problem because child classes have to implement it, But it does not seem correct to me to create an unnecessary instance to call a method.

So, is there any solution to enforce child classes to implement getFooBar() method? if not, how can I throw the NotImplementedException instead of NullPointerException?

Jose
  • 1,857
  • 1
  • 16
  • 34

6 Answers6

5

is there any solution to enforce child classes to implement getFooBar() method?

Not for static methods. Static methods are tied to the specific class, so they can't be inherited, nor abstract or virtual.

If you want to make the method polymorphic it needs to be an instance method.

how can I throw the NotImplementedException instead of NullPointerException

The result you're getting that exception is because the type does not have a GetFooBars method, so method is null. So you could check for null first:

public void showFooBarizables(){

    MethodInfo method = type.GetMethod("GetFooBars");

    if(method == null)
        throw new NotImplementedException();

    IEnumerable<FooBarizable> FooBars = (IEnumerable<FooBarizable>)method.invoke(null, null);

    show(FooBars);
}

But throwing that exception is a little misleading because it may seem to the caller that the showFooBarizables method is not implemented, not the underlying GetFooBars.

Since these method seem to be factory methods, perhaps you need a factory for each type instead? It seems like you are trying to use generics as a replacement for overloads. Factory methods generally aren't generic since they have to have different logic for each type. You could create a "base" factory that contains common code, then sub-class the factory for each specific type.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
4

Of course .NET doesn't allow you to write virtual static methods :)

The whole point of virtual methods is that when you call the Base.DoSomething method on an instance of type Derived, it's the code in Derived.DoSomething that executes. But that means you need the instance to know its actual runtime type, so that you know what method is really supposed to be executed.

A typical alternative is to use some form of a factory interface. That is, instead of querying Foo.GetFooBars or Bar.GetFooBars, you'll get an instance of a provider of the relevant instance type, e.g. Fooizer.GetFooBars and Barizer.GetFooBars, where both Fooizer and Barizer implement IFooBarProvider. GetFooBars doesn't fit into the FooBarizable interface - because that's not where it belongs. Object-oriented design, responsibility, substitution principles and all that :)

Then, if you need to enforce the implementation in code (e.g. to make sure someone doesn't forget to implement the proper provider), you could make an abstract instance method or property on your type:

public abstract class FooBarizable
{
  protected abstract IFooBarProvider GetDefaultProvider();
}

Depending on what you're actually trying to do, it might make sense to make those classes generic. Or not :)

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • I'll look for all that concepts and give it a try, thanks for your answer. – Jose Apr 20 '16 at 13:50
  • Ok, thats what I've understood: I have to create a Factory of Providers, then get the correspondant provider instance of each Foobarizable class, and this solves the responsibility problem(that I didn't saw before). Then, I still having the same problem, I cannot get the DefaultProvider of Foo/Bar if I dont have an instance of Foo/Bar, because getDefaultProvider is not static. So, how can I get an instance of the concrete provider, having in mind that the only thing that I know in the FooBarManager, is the Type, stored in a variable. Correct me if I am wrong at any point. – Jose Apr 20 '16 at 14:48
  • 1
    @Kirenenko The two main approaches are registration and reflection. Registration is simple - just have a static class that has all the providers in a dictionary based on type. Reflection would mean something like "find all types that implement `IFooBarProvider`". Finally, you may find that there's no reason to have a generic solution that works with a type not known at compile-time - the more you deal with the likes of dependency injection and explicit typing, the more you'll find that most of the things can be known statically at compile time. – Luaan Apr 20 '16 at 17:45
  • 1
    @Kirenenko Sometimes it helps to look at your problem and inverting it - e.g. using push-approaches instead of pull-approaches and vice versa. A lot of the time, a complicated thing becomes embarassingly simple. – Luaan Apr 20 '16 at 17:46
  • I've ended with this approach, passing an instance of the provider instead of the type. – Jose Jul 15 '16 at 11:43
2

You cannot force child classes to define a static methods. As you noted, abstract methods cannot be static, and interfaces work with instances only. I think you are trying to put too much into a single class. It looks like your trying to create some franken-factory. Instead just separate the factory functionality and the abstract parent object.

public abstract class FooBarizable {
    public string Name { get; set; }
}

Factory example:

public static class FooBarizableFactory {

    public static IEnumerable<FooBarizable> GetFooBars(Type type){
        var parentType = typeof(FooBarizable);          
        if (!parentType.IsAssignableFrom(type))
            throw new ArgumentException("Not a FooBarizable");                  

        switch(type.Name) {
            case "Foo":
                return new List<Foo>() { new Foo () };

            case "Bar":
                return new List<Bar>() { new Bar() };

            default:
                throw new ArgumentException("Not a known FooBarizable");
        }
    }
}

Usage:

var fooBars = FooBarizableFactory.GetFooBars(typeof(Foo));

Demo of idea.

ryanyuyu
  • 6,366
  • 10
  • 48
  • 53
  • Looks like the Factory is the way to go as various of you have pointed out, Thanks from the Franken-coder :) – Jose Apr 20 '16 at 13:59
  • But...I think that a switch-case doesn't fit with generics, correct me if I am wrong. – Jose Apr 20 '16 at 14:08
  • @Kirenenko notice it is switching on the `type.Name` (a string). There are probably less brittle ways of switching on the type, but this is a proof-of-concept. – ryanyuyu Apr 20 '16 at 14:55
  • Its not about the type.Name, its more about of, if I add a new FooBarizable class to the scheme, I want to only do the `: FooBarizable` part and not search for every switch case in my code that containts it. – Jose Apr 20 '16 at 15:54
  • 1
    @Kirenenko the idea with a Factory is that you have the switch statement in exactly one place. If you add a new class, you'll have to implement that logic somewhere. With a factory, you know exactly where to go to implement it. Anything else that doesn't need the switching logic can go into the class itself (or the parent class). – ryanyuyu Apr 20 '16 at 15:57
1

.Net does not allow to define static abstract methods

Because C# compiler makes static as abstract and sealed. So you can't make it just abstract or sealed.

The problem is that when I call MethodInfo method = type.GetMethod("GetFooBars"); in the manager, if the subclase does not implements the method, method is null, and NullPointerExceptionis called instead.

I said static is abstract and sealed. So because of it's sealed derived class will not have GetFooBars method.

You can use the BindingFlags.FlattenHierarchy flag. That way it will check also protected and public static classes of base classes. If It's not implemented on derived class it will check base class. So in your stiuation base class GetFooBars will called, if the derived one does not have this method.

Community
  • 1
  • 1
Erkan Demirel
  • 4,302
  • 1
  • 25
  • 43
0

There's no way to enforce static methods via any form of inheritance or polymorphism, but a potential workaround would be to implement an extension method(s) for FooBarizable, so that any class that inherits it will have access to the extension.

AntiTcb
  • 609
  • 4
  • 15
0

Static methods are not related to the object (instance) of the class, it is always related to the class itself.

One way to enforce the implementation of a method would be the use of an interface. Another way, and this is what I think you want, since this method will have different behavior in different instances, would be the use of abstract methods.

public abstract class AbstractClass 
{
    public abstract int MustIMplementThis(string param1);
}

public class ChildClass : AbstractClass
{

    public override int MustIMplementThis(string param1)
    {
        throw new NotImplementedException();
    }
}

All classes that inherits from AbstracClass will have to implement the methods listed on the parent class.

Ralph
  • 131
  • 10
  • I see, but since the methods will have different behaviors, you'll have to have an instance. – Ralph Apr 20 '16 at 14:14
  • Well, Im doing it without an instance atm, just not enforcing the implementation. – Jose Apr 20 '16 at 14:54