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

时间:2009-04-30 23:17:47

标签: c#

我有以下代码:

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.
    }
}

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

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

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

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

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

感谢您的投入!


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

    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 个答案:

答案 0 :(得分:27)

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

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

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

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

答案 1 :(得分:10)

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

 MyGenericBase<Anything>.StaticMethod( null );

答案 2 :(得分:2)

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

答案 3 :(得分:1)

您可以执行以下操作之一:

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

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

答案 4 :(得分:-1)

因为它是9年前,所以我知道它已经很多年了。我继续实践C#,而不关心rl的实现。我认为您的帖子在进行继承,OOAD或封装(信息隐藏)方面没有目标。

从您的代码到这里的我的代码。

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