简体   繁体   English

C#:“无法创建静态类的实例”

[英]C#: “Cannot create an instance of the static class”

I'm in the process of converting some Java code to C# and stumbled across the following curious thing: 我正在将一些Java代码转换为C#,偶然发现以下奇怪的事情:

public interface IActivation {
    public abstract double func(double inputput);

    public static class S1 : IActivation {
        public double func(double input) {
            if (input > 0) return 1.0;
            return 0.0;
        }
    }
}

SomewhereElse (usage): SomewhereElse(用法):

protected IActivation activation = new IActivation.S1();

Looking at the original code, it's clear what the intention of this was: 看一下原始代码,很清楚这是什么意思:

  1. Declare an interface and nested within it several static implementations of that interface (the code contains other implementations of IActivation, eg "S2", "S3" etc. which were omitted here). 声明一个接口并在其中嵌套该接口的几个静态实现(该代码包含IActivation的其他实现,例如“S2”,“S3”等,这里省略了)。
  2. The typical usage scenario for this was to assign a variable to one specific implementation of that interface. 这种情况的典型使用场景是将变量分配给该接口的一个特定实现。 Also, by the way you'd need to instantiate that variable, it's perfectly clear where those specific implementations belong to - in a manner of speaking, the nested declaration would further increase the readability of the code (eg new IActivation.S1(); makes it clear that S1 is a specific implementation of IActivation). 此外,通过您需要实例化该变量的方式,非常清楚这些特定实现所属的位置 - new IActivation.S1();来说,嵌套声明将进一步提高代码的可读性(例如, new IActivation.S1();清楚地表明S1是IActivation的具体实现)。

Interestingly, C# does not like the way the whole thing is defined: " Cannot create an instance of the static class 'IActivation.S1 ". 有趣的是,C#并不喜欢定义整个事物的方式:“ 无法创建静态类'IActivation.S1的实例 ”。 Does anyone know a way of how to refactor that code so that 1. and 2. would be preserved? 有没有人知道如何重构该代码的方式,以便1.和2.将被保留?

In Java, a static inner class has no implicit access to the members of its enclosing type. 在Java中, static内部类没有对其封闭类型成员的隐式访问。 In C#, all nested types have no such access to their parent type's members; 在C#中, 所有嵌套类型都没有对父类型成员的访问权限; there is no modifier you need to add in C# to trigger this behavior. 您无需在C#中添加修饰符来触发此行为。

In C#, static classes are abstract sealed , so they cannot be created nor derived -- this is not the same meaning as in Java. 在C#中, static类是abstract sealed ,因此它们不能被创建或派生 - 这与Java中的含义不同。 Additionally, interfaces cannot contain type declarations of their own. 此外,接口不能包含自己的类型声明。

Try something like this: 尝试这样的事情:

public interface IActivation {
    double Func(double inputput);
}

public class S1 : IActivation {
    public static readonly S1 Instance = new S1();

    private S1() { }

    public double Func(double input) {
        if (input > 0) return 1.0;
        return 0.0;
    }
}

If your goal is to provide default implementations in some "readable" way (though I dispute that IActivator.S1() is inherently more readable...) then you could create a static factory class: 如果您的目标是以某种“可读”的方式提供默认实现(尽管我认为IActivator.S1()本质上更具可读性......)那么您可以创建一个静态工厂类:

public static class Activator
{
    public static S1 S1
    {
        get
        {
            return S1.Instance;

            // Or you could do this if you make the S1 constructor public:
            // return new S1();
        }
    }
}

However, I dispute the claim that this is more readable or helpful. 但是,我对这个更具可读性或更有帮助的说法提出质疑。 Visual Studio will, when constructing an object in the context of a particular type, display all of that type's subtypes. 当在特定类型的上下文中构造对象时,Visual Studio将显示该类型的所有子类型。 So if you do this ( | represents the cursor): 所以如果你这样做( |代表游标):

IActivator foo = new |

You should get a neat list of all of the classes in your current scope that implement IActivotor. 您应该获得当前作用域中实现IActivotor的所有类的简洁列表。

不要将您的类标记为static

The error message itself is clear, the S1 class cannot be static since you are creating an instance of it. 错误消息本身很清楚,S1类不能是静态的,因为您正在创建它的实例。 Remove the static keyword from S1. 从S1中删除static关键字。 Also, the access modifier and abstract modifier are invalid in an interface declaration. 此外,访问修饰符和抽象修饰符在接口声明中无效。

In C#, interfaces cannot declare inner types. 在C#中,接口不能声明内部类型。

My suggestion here is to use the Factory pattern to get the correct instances instead of nesting types in your interface (this increases coupling/dependencies). 我的建议是使用Factory模式来获取正确的实例而不是接口中的嵌套类型(这会增加耦合/依赖关系)。

interface IActivation
{
    double func(double inputput);
}

public static class ActivationFactory
{
    IActivation GetImplA()
    {
        return new ImplA();
    }

    IActivation GetImplB()
    {
        return new ImplB();
    }
}

class ImplA : IActivation { }
class ImplB : IActivation { }

If IActivation does not have to be an interface, you can turn it into an abstract class 如果IActivation不必是接口,则可以将其转换为抽象类

public abstract class IActivation
{
    public abstract double func(double inputput);

    public class S1 : IActivation
    {
        public override double func(double input)
        {
            if (input > 0) return 1.0;
            return 0.0;
        }
    }
}

This changes the actual meaning of the code, but allows you to say 这改变了代码的实际含义,但允许你说

var s1 = new IActivation.S1();

Update The main issue I can think of is if you have a class that extends something else and implements this interface it won't work (you can't inherit from two classes). 更新我能想到的主要问题是,如果你有一个扩展别的东西并实现这个接口的类它将无法工作(你不能从两个类继承)。 You could then create an interface and an abstract class that implements the abstract class but that's getting a little silly. 然后,您可以创建一个接口和一个实现抽象类的抽象类,但这有点傻。

Another option is 另一种选择是

public interface IActivation {
    // ...
}

public class Activation {
    public class S1 : IActivation { 
        // ...
    }
}

The advantage is you keep IActivation as an interface, but you have another class littering your namespace. 优点是您将IActivation保留为接口,但是您有另一个类乱丢您的命名空间。

In both cases, you haven't done a direct port from Java. 在这两种情况下,您还没有从Java完成直接端口。

use sigleton pattern for each S'i' implementation and tear appart interface and implementation as described above by cdhowie 使用sigleton模式为每个S'i'实现和撕裂appart接口和实现如上所述由cdhowie

It seems you don't need factory - unless your S'i' instances have own state? 看来你不需要工厂 - 除非你的S'i'实例有自己的状态?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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