从通用抽象类调用静态方法而不指定类型

时间:2017-05-22 20:19:21

标签: c# generics static abstract-class

我有一个这样的抽象类:

public abstract class BaseCamera<TCamera> : ICamera where TCamera : ManagedCameraBase
{
    public static uint GetNumberOfCameras()
    {
        using (var bus = new ManagedBusManager())
        {
            bus.RescanBus();
            return bus.GetNumOfCameras();
        }
    }
}

想要这样称呼它: BaseCamera.GetNumberOfCameras()

这对我来说很有意义,因为因为这是一个抽象类,所以只有具体的子类必须选择TCamera,并且基类想要获得所有相机的数量,无论它们是什么类型。

但是,编译器不批准:

  

使用Generic类型&#39; BaseCamera&#39;需要1种类型   参数。

是否有某种方法或我是否需要为此创建一个新类?

我认为值得指出的是ManagedCameraBase是来自外部API的一个类。因此,我不想将其包含在BaseCamera的任何调用中,这就是我尝试避免指定类型的原因。

3 个答案:

答案 0 :(得分:3)

  

因为这是一个抽象类,所以只有具体的子类必须选择TCamera

这不是泛型如何运作的。这与abstract类没有任何关系。如果该类是通用的并且不是抽象,那么仍然需要指定一个泛型参数,以便调用该类的静态方法。最重要的是,没有什么可以说子类不能是通用的。你可能不会这样,但没有什么要求是这样的。

现在,在您的特定情况下,GetNumberOfCameras方法根本不使用泛型参数(T),因此无关紧要什么是泛型参数你提供,你可以放入你想要的任何东西,它会工作得很好。当然,正因为如此,这表明这个方法可能不属于这个类;它可能应该在这个类也使用的另一个类中。

答案 1 :(得分:1)

这就是问题所在。静态方法GetNumberOfCameras属于包含它的类,但是泛型类实际上被编译为每种类型的单独类。所以,例如,如果你有这个:

public class Foo<T>
{
    static int foo = 0;

    public static void IncrementFoo()
    {
        foo++;
    }

    public static int GetFoo()
    {
        return foo;
    }
}

然后你这样做了:

Foo<string>.IncrementFoo();
Console.WriteLine(Foo<string>.GetFoo());
Console.WriteLine(Foo<int>.GetFoo());

您将看到第一次调用GetFoo将返回一个,但第二次调用将返回零。 Foo<string>.GetFoo()Foo<int>.GetFoo()两个独立的静态方法,属于两个不同的类(并访问两个不同的字段)。这就是你需要一个类型的原因。否则,编译器不知道要调用哪个类的静态方法。

您需要的是一个非泛型基类,供您的泛型类继承。所以,如果你这样做:

public class Foo<T> : Foo
{

}

public class Foo
{
    static int foo = 0;

    public static void IncrementFoo()
    {
        foo++;
    }

    public static int GetFoo()
    {
        return foo;
    }
}

然后这个:

Foo<string>.IncrementFoo();
Console.WriteLine(Foo<string>.GetFoo());
Console.WriteLine(Foo<int>.GetFoo());

首先会给你你可能期望的东西。换句话说,对GetFoo的两次调用都会返回相同的结果。当然,您实际上不再需要类型参数,而且可以这样做:

Foo.IncrementFoo();

当然,另一种方法是将静态方法移到一个完全不同的类中,如果它没有理由它应该成为BaseCamera的一部分

答案 2 :(得分:0)

嗯,这里有一些你需要更好地理解的东西。

首先,我发现您的设计存在问题。你试图坚持这个类的方法实际上与它的通用性质无关。实际上,你正在实例化另一个类来完成这项工作,所以它根本就不属于这里。

如果它实际上与从ManagedCameraBase继承的对象有关,则该方法可能不需要是静态的,而是实例方法。然后,您可以根据使用情况决定访问者(公共/私人)。

最后,您需要了解Generics实际上做了什么。当您使用具有特定类型的通用基础时,编译器会在幕后为您创建基础专用类型。如果您要使用静态方法,则编译器需要知道您要定位的类型,以便创建将为您的调用提供服务的静态实例。因此,如果调用静态方法,则必须传递一个类型,最终会得到与用于调用它的类型一样多的静态实例(当然,类型必须从ManagedCameraBase派生)。

正如您所看到的,您应该将该方法移动到某个帮助器类或类似的东西,或者使其成为非静态的实例方法。