C#编译器:无法在非静态上下文中访问静态方法

时间:2021-07-18 16:08:24

I have the code below :

我有以下代码:

public class Anything
{
    public int Data { get; set;}
}

public class MyGenericBase<T>
{
    public void InstanceMethod(T data)
    {
        // do some job
    }

    public static void StaticMethod(T data)
    {
        // do some job
    }

    // others members...
}

public sealed class UsefulController : MyGenericBase<Anything>
{
    public void ProxyToStaticMethod()
    {
        StaticMethod(null);
    }

    // others non derived members...
}

public class Container
{
    public UsefulController B { get; set; }
}

public class Demo
{
    public static void Test()
    {
        var c = new Container();
        c.B.InstanceMethod(null);   // Works as expected.
        c.B.StaticMethod(null);     // Doesn't work. 
                                    // Static method call on object rather than type. 
                                    // How to get the static method on the base type ?
        c.B.ProxyToStaticMethod();  // Works as expected.
    }
}

The compiler is very angry... I understand the error message but I don't know how to solve this. I was trying to get a type rather than an object to make my static method call, but I don't find the way to do it correctly. Moreover this results in something not elegant at all.

编译器非常生气......我理解错误信息,但我不知道如何解决这个问题。我试图获取一个类型而不是一个对象来进行静态方法调用,但我找不到正确的方法。而且这导致一些不优雅的东西。

Basically, the GenericBase is a class from a framework with a lot of static methods and some instance methods. The controller is typing this class and extending it.

基本上,GenericBase是来自具有许多静态方法和一些实例方法的框架的类。控制器正在键入此类并进行扩展。

The container is a group of logical related controllers.

容器是一组逻辑相关的控制器。

Interesting thing : a Java version of this code compiles correctly, but with a warning. The execution is correct, too.

有趣的事情:这个代码的Java版本正确编译,但有一个警告。执行也是正确的。

Does it exist a design pattern to solve this ?

是否存在解决此问题的设计模式?

Thanks for your inputs !

感谢您的投入!


I found a way to get rid of this problem, thanks to your answers. It seems to work, but I can not tell if there are side effects right know.

由于你的答案,我找到了摆脱这个问题的方法。它似乎有效,但我不知道是否有副作用正确知道。

    public class GenericBase<T> : MyGenericBase<T>
{
    // Create instance calls here for every base static method.
}

public sealed class UsefulController : GenericBase<Anything>
{
    // others non derived members...
}

5 个解决方案

#1


A call to a static method will be compiled to call a specific static method on a specific class. In other words, it won't use the contents of B to determine which static method to call.

将编译对静态方法的调用以调用特定类上的特定静态方法。换句话说,它不会使用B的内容来确定调用哪个静态方法。

So the call has to be resolvable at compile time, hence it complains, because for all it knows, you could replace the contents of that property with multiple concrete types, which would mean that the call to the static method would have to be resolved to a static method in either of these classes.

所以调用必须在编译时可以解析,因此它会抱怨,因为它知道所有内容都可以用多种具体类型替换该属性的内容,这意味着必须将对静态方法的调用解析为这两个类中的静态方法。

The compiler does not have anything like a virtual or abstract static method, so for one you can't guarantee that all of those classes have that static method. And since the call has to be resolvable at compile time, it won't work like that.

编译器没有像虚拟或抽象静态方法那样的东西,所以对于一个,你不能保证所有这些类都有静态方法。因为调用必须在编译时可以解析,所以它不会像那样工作。

You can, as you've noticed, call an instance method of the object, which in turn calls the static method. This does not invalidate the above rules since when the compiler compiles that instance method, which static method it will call is constant and known.

正如您所注意到的,您可以调用对象的实例方法,该方法又调用静态方法。这不会使上述规则无效,因为当编译器编译该实例方法时,它将调用哪个静态方法是常量且已知的。

#2


To call the static method you need to refer to it from the class it's defined in, not an instance of that class.

要调用静态方法,您需要从它定义的类中引用它,而不是该类的实例。

 MyGenericBase<Anything>.StaticMethod( null );

#3


You can't do this in C#. You can do it in VB.NET and Java, but honestly, it doesn't really make sense. It just gives you a false sense of polymorphism in a static method, which is not real by any means. Since it's not polymorphic, the whole method call is known at compile time (statically) and you could mention the call directly with the class name.

你不能在C#中做到这一点。你可以用VB.NET和Java做到这一点,但说实话,它并没有多大意义。它只是在静态方法中给你一种错误的多态性,这在任何方面都是不现实的。由于它不是多态的,整个方法调用在编译时(静态)是已知的,你可以直接用类名来提及调用。

#4


You can do one of those:

你可以做其中一个:

UsefulController.StaticMethod(null);  
MyGenericBase<Anything>.StaticMethod(null);  

Using the instance is not possible, as already explained by others.

正如其他人已经解释的那样,使用该实例是不可能的。

#5


Since it is 9 years ago, I know it is way too many years ago. I go ahead and practiced C# without caring rl implementation. I think that your post has no goal in doing inheritance, OOAD, nor encapsulation (info hiding).

从9年前开始,我知道这是多年前的事了。我继续练习C#,没有关心rl的实现。我认为你的帖子没有继承,OOAD和封装(信息隐藏)的目标。

From your code to my code here.

从你的代码到我的代码。

public class Anything
{
    private int data, data2; //field

    public Anything()
    {
        data = default(int);
    }
    public int Data { get; set; }
}

public class GenericParentClass<T>
{
    public static void StaticMethod(T data)
    {
        // do some job
    }

    public void InstanceMethod(T data)
    {
        // do some job
    }
}

public sealed class UsefulController<T> : GenericParentClass<T> where  T : Anything, new()
{
    //all static public methods must be placed before all non-static public methods. [StyleCop Rule: SA1204]
    public static new void StaticMethod(T data)  //'UsefulController'.StaticMethod(Anything) hides inherited member 'GenericParentClass<Anything>.StaticMethod(Anything)'. Use the new keyword if hiding was intended.
    {
        GenericParentClass<T>.StaticMethod(data);  //'data' is a variable but used like a type //arugement type T is not assignable to parameter type 'data'.
    }

    public void EncapsulatedStaticMethod()
    {
        T @class = new T(); //cannot create an instance of the variable type T because it does not have the new() constraint. //T is type and @class is variable and new is an instance.
        StaticMethod(@class);  
    }

    public void EncapsulatedInstanceMethod(T data)
    {
        base.InstanceMethod(data);
    }
}

public class Container
{
    public UsefulController<Anything>  B { get; set; }
}

public class Testing   
{
    public static void Main()
    {
        Anything @var = new Anything();
        var c = new Container();
        c.B.InstanceMethod(null);   
        c.B.EncapsulatedStaticMethod();    
        c.B.EncapsulatedInstanceMethod(var);  
    }
}

#1


A call to a static method will be compiled to call a specific static method on a specific class. In other words, it won't use the contents of B to determine which static method to call.

将编译对静态方法的调用以调用特定类上的特定静态方法。换句话说,它不会使用B的内容来确定调用哪个静态方法。

So the call has to be resolvable at compile time, hence it complains, because for all it knows, you could replace the contents of that property with multiple concrete types, which would mean that the call to the static method would have to be resolved to a static method in either of these classes.

所以调用必须在编译时可以解析,因此它会抱怨,因为它知道所有内容都可以用多种具体类型替换该属性的内容,这意味着必须将对静态方法的调用解析为这两个类中的静态方法。

The compiler does not have anything like a virtual or abstract static method, so for one you can't guarantee that all of those classes have that static method. And since the call has to be resolvable at compile time, it won't work like that.

编译器没有像虚拟或抽象静态方法那样的东西,所以对于一个,你不能保证所有这些类都有静态方法。因为调用必须在编译时可以解析,所以它不会像那样工作。

You can, as you've noticed, call an instance method of the object, which in turn calls the static method. This does not invalidate the above rules since when the compiler compiles that instance method, which static method it will call is constant and known.

正如您所注意到的,您可以调用对象的实例方法,该方法又调用静态方法。这不会使上述规则无效,因为当编译器编译该实例方法时,它将调用哪个静态方法是常量且已知的。

#2


To call the static method you need to refer to it from the class it's defined in, not an instance of that class.

要调用静态方法,您需要从它定义的类中引用它,而不是该类的实例。

 MyGenericBase<Anything>.StaticMethod( null );

#3


You can't do this in C#. You can do it in VB.NET and Java, but honestly, it doesn't really make sense. It just gives you a false sense of polymorphism in a static method, which is not real by any means. Since it's not polymorphic, the whole method call is known at compile time (statically) and you could mention the call directly with the class name.

你不能在C#中做到这一点。你可以用VB.NET和Java做到这一点,但说实话,它并没有多大意义。它只是在静态方法中给你一种错误的多态性,这在任何方面都是不现实的。由于它不是多态的,整个方法调用在编译时(静态)是已知的,你可以直接用类名来提及调用。

#4


You can do one of those:

你可以做其中一个:

UsefulController.StaticMethod(null);  
MyGenericBase<Anything>.StaticMethod(null);  

Using the instance is not possible, as already explained by others.

正如其他人已经解释的那样,使用该实例是不可能的。

#5


Since it is 9 years ago, I know it is way too many years ago. I go ahead and practiced C# without caring rl implementation. I think that your post has no goal in doing inheritance, OOAD, nor encapsulation (info hiding).

从9年前开始,我知道这是多年前的事了。我继续练习C#,没有关心rl的实现。我认为你的帖子没有继承,OOAD和封装(信息隐藏)的目标。

From your code to my code here.

从你的代码到我的代码。

public class Anything
{
    private int data, data2; //field

    public Anything()
    {
        data = default(int);
    }
    public int Data { get; set; }
}

public class GenericParentClass<T>
{
    public static void StaticMethod(T data)
    {
        // do some job
    }

    public void InstanceMethod(T data)
    {
        // do some job
    }
}

public sealed class UsefulController<T> : GenericParentClass<T> where  T : Anything, new()
{
    //all static public methods must be placed before all non-static public methods. [StyleCop Rule: SA1204]
    public static new void StaticMethod(T data)  //'UsefulController'.StaticMethod(Anything) hides inherited member 'GenericParentClass<Anything>.StaticMethod(Anything)'. Use the new keyword if hiding was intended.
    {
        GenericParentClass<T>.StaticMethod(data);  //'data' is a variable but used like a type //arugement type T is not assignable to parameter type 'data'.
    }

    public void EncapsulatedStaticMethod()
    {
        T @class = new T(); //cannot create an instance of the variable type T because it does not have the new() constraint. //T is type and @class is variable and new is an instance.
        StaticMethod(@class);  
    }

    public void EncapsulatedInstanceMethod(T data)
    {
        base.InstanceMethod(data);
    }
}

public class Container
{
    public UsefulController<Anything>  B { get; set; }
}

public class Testing   
{
    public static void Main()
    {
        Anything @var = new Anything();
        var c = new Container();
        c.B.InstanceMethod(null);   
        c.B.EncapsulatedStaticMethod();    
        c.B.EncapsulatedInstanceMethod(var);  
    }
}