来自子句

时间:2016-04-20 12:37:34

标签: c# .net generics

我创建了一个抽象类,我们称之为FooBarizable,即2个clases(在实践中更多),FooBar的父级。现在,我有一个FooBarizableManager来管理FooBar个类,具体取决于他的类型。从FroobarizableManager开始,我想打电话给getFooBarizables()。让我们看看结构:

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);
    }

    ...

}

所以,我的问题是我想从管理器中获取对象集合,使用类型,但强制子类来实现getFooBars()方法。

我遇到的问题:

  • .Net不允许定义静态抽象方法,因此我无法创建public static abstract IEnumerable<FooBarizable> GetFooBars()并强制实施子类来实现它。

  • 实现的方式并不强制在子类中实现该方法,但我尝试至少抛出NotImplementedException。问题是当我在管理器中调用MethodInfo method = type.GetMethod("GetFooBars");时,如果子类化酶没有实现该方法,method为空,而是调用NullPointerException

  • 我试图创建一个实例方法而不是静态的静态方法,它解决了强制问题,因为子类必须实现它,但是我创建一个不必要的实例来调用它似乎不正确方法。

那么,是否有任何解决方案来强制子类实现getFooBar()方法?如果没有,我怎样才能抛出NotImplementedException而不是{{1 }}

6 个答案:

答案 0 :(得分:4)

  

是否有任何解决方案来强制子类实现getFooBar()方法?

不适用于静态方法。静态方法与特定类相关联,因此它们不能被继承,也不能被抽象或虚拟。

如果要使方法具有多态性,则需要使用实例方法。

  

如何抛出NotImplementedException而不是NullPointerException

您获得该异常的结果是因为该类型没有 GetFooBars方法,因此methodnull。所以你可以首先检查null:

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);
}

但抛出该异常有点误导,因为调用者似乎没有实现showFooBarizables方法,而不是基础GetFooBars

由于这些方法似乎是工厂方法,或许您需要为每种类型设置工厂?您似乎正在尝试使用泛型作为重载的替代品。工厂方法通常不是通用的,因为它们必须为每种类型具有不同的逻辑。您可以创建一个包含公共代码的“基础”工厂,然后为每种特定类型对 factory 进行子类化。

答案 1 :(得分:4)

当然.NET不允许你编写虚拟静态方法:)

虚拟方法的重点在于,当您在Base.DoSomething类型的实例上调用Derived方法时,它是Derived.DoSomething中执行的代码。但这意味着你需要实例知道它的实际运行时类型,以便你知道应该执行什么方法。

典型的替代方案是使用某种形式的工厂界面。也就是说,您将获得相关实例类型的提供者的实例,而不是查询Foo.GetFooBarsBar.GetFooBarsFooizer.GetFooBarsBarizer.GetFooBars,其中FooizerBarizer都实现了IFooBarProviderGetFooBars不适合FooBarizable界面 - 因为它不属于它所在的位置。面向对象的设计,责任,替代原则以及所有这些:)

然后,如果您需要在代码中强制执行(例如,为了确保有人不忘记实现正确的提供程序),您可以在您的类型上创建一个抽象实例方法或属性:

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

根据您实际尝试的内容,将这些类设为通用可能是有意义的。或者不是:)

答案 2 :(得分:2)

您不能强制子类定义静态方法。如您所述,抽象方法不能是静态的,interfaces work with instances only。我认为你试图把太多的东西放到一个班级。看起来你想要创建一些法兰克工厂。而只是将工厂功能和抽象父对象分开。

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

工厂示例:

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");
        }
    }
}

用法:

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

Demo的想法。

答案 3 :(得分:1)

  

.Net不允许定义静态抽象方法

因为C#编译器使静态为抽象和密封。所以你不能把它简单化为抽象或密封。

  

问题是当我调用MethodInfo方法=时   type.GetMethod(&#34; GetFooBars&#34);在经理中,如果亚类酶没有   实现方法,方法为null,并且NullPointerExceptionis   而是打来电话。

我说静电是抽象的和密封的。因此,由于它的密封派生类不会有GetFooBars方法。

您可以使用BindingFlags.FlattenHierarchy flag。这样它将检查基类的受保护和公共静态类。如果它没有在派生类上实现,它将检查基类。因此,如果派生的类没有这种方法,那么在你的stiuation基类中将调用GetFooBars

答案 4 :(得分:0)

无法通过任何形式的继承或多态来强制执行静态方法,但潜在的解决方法是为FooBarizable实现扩展方法,以便任何继承它的类都可以访问扩展名。

答案 5 :(得分:0)

静态方法与类的对象(实例)无关,它始终与类本身相关。

强制执行方法的一种方法是使用接口。 另一种方式,这就是我认为你想要的,因为这种方法在不同的实例中会有不同的行为,会使用抽象方法。

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

public class ChildClass : AbstractClass
{

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

从AbstracClass继承的所有类都必须实现父类中列出的方法。