简体   繁体   中英

Call static method from generic abstract class without specifying a type

I have an abstract class like this:

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

And want to call it like this: BaseCamera.GetNumberOfCameras()

It makes sense to me, because since this is an abstract class, only the concrete children classes must choose a TCamera , and the base class wants to get the number of all cameras, no matter they type.

However, the compiler does not approve:

Using the Generic type 'BaseCamera' requires 1 type arguments.

Is there some way around it or do I need to create a new class just for this?

I think it is worth pointing out that ManagedCameraBase is a class from an external API I'm wrapping. Therefore, I do not want to include it in any of my calls for BaseCamera and that is why I'm trying to avoid specifying a type.

because since this is an abstract class, only the concrete children classes must choose a TCamera

That's not how generics work. This has nothing at all to do with the class being abstract . If the class was generic and not abstract you would still need to specify a generic argument in order to call a static method of the class. On top of that, there's nothing to say that a child class can't also be generic. Yours may happen to not be, but there's nothing requiring that to be the case.

Now, in your particular case, the GetNumberOfCameras method doesn't use the generic argument ( T ) at all, so it doesn't matter what generic argument you provide, you can put in whatever you want and it'll work just fine. Of course, because of that, it's a sign that this method probably doesn't belong in this class; it should probably be in another class that this class also uses.

Here's the problem. The static method GetNumberOfCameras belongs to the class that contains it, but a generic class actually gets compiled into separate classes for each type. So, for example if you had this:

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

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

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

And then you did this:

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

You will see that the first call to GetFoo will return one, but the second will return zero. Foo<string>.GetFoo() and Foo<int>.GetFoo() are two separate static method that belong to two different classes (and access two different fields). So that's why you need a type. Otherwise the compiler won't know which static method of which class to call.

What you need is a non-generic base class for your generic class to inherit from. So if you do this:

public class Foo<T> : Foo
{

}

public class Foo
{
    static int foo = 0;

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

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

Then this:

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

Will give you what you might have expected at first. In other words, both calls to GetFoo will return the same result. And, of course, you don't actually need the type argument anymore and can just do:

Foo.IncrementFoo();

Or course, the alternative is to just move your static methods into an entirely different class if there's no reason why it should be part of BaseCamera

Well, there are a couple of things here you need to understand better.

First of all, I see a problem with your design. The method you are attempting to stick into this class really has nothing to do with the generic nature of it. In fact, you are instantiating another class to do the job so it really does not belong here at all.

If it actually had something to do with an object that inherits from ManagedCameraBase, the method would probably not need to be static but rather an instance method. You can then decide on the accessor (public/private) based on usage.

Finally, you need to understand what Generics actually do under the covers. When you use the generic base with a particular type, an underlying specialized type is created for you behind the scenes by the compiler. If you were to use the static method, the compiler would need to know the type you are targeting in order to create the static instance that will serve your call. Because of this, if you call the static method, you must pass a type and you will end up with as many static instances as the types you use to call it (the types must derive from ManagedCameraBase, of course).

As you can see, you should either move that method out to some helper class or something of the sort, or make it a non-static, instance method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM