【问题标题】:C# Compiler : cannot access static method in a non-static contextC# 编译器:无法在非静态上下文中访问静态方法
【发布时间】:2010-10-23 00:18:33
【问题描述】:

我有以下代码:

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

【问题讨论】:

    标签: c#


    【解决方案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);  
        }
    }
    

    【讨论】:

      【解决方案2】:

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

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

      正如其他人已经解释的那样,无法使用实例。

      【讨论】:

      • 谢谢!我已经注意到了这一点。我正在寻找一种通过容器进行这些调用的方法。您认为首先将基类派生到另一个基类(包括对静态方法的实例调用),然后从它派生?
      • 如果你认为你“需要”这个实例调用,只需添加你的代理方法。我的建议是尽量保持 API 简洁明了。
      • 由于我无法使用包含类直接调用静态成员,因此它似乎是目前唯一的解决方案。我同意尽可能保持 API 干净。
      【解决方案3】:

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

       MyGenericBase<Anything>.StaticMethod( null );
      

      【讨论】:

      • 谢谢!我已经注意到了这一点。我正在寻找一种通过容器进行这些调用的方法。您认为首先将基类派生到另一个基类(包括对静态方法的实例调用),然后从它派生?
      【解决方案4】:

      您不能在 C# 中执行此操作。您可以在 VB.NET 和 Java 中做到这一点,但老实说,这并没有什么意义。它只是给您一种static 方法中的多态性的错误感觉,这无论如何都不是真实的。由于它不是多态的,因此整个方法调用在编译时(静态)是已知的,您可以直接使用类名来提及调用。

      【讨论】:

        【解决方案5】:

        对静态方法的调用将被编译为调用特定类的特定静态方法。也就是说,它不会使用 B 的内容来决定调用哪个静态方法。

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

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

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

        【讨论】:

        • 非常有指导意义,谢谢!阅读下面的答案,我想知道一个可能的解决方案。欢迎发表评论。
        • 毕竟,它们不是无缘无故被称为 STATIC 的
        猜你喜欢
        • 2015-10-21
        • 2011-11-03
        • 2017-03-03
        • 1970-01-01
        • 1970-01-01
        • 2018-05-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多