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

时间:2011-08-22 11:20:47

标签: c# java .net static

我正在将一些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(用法):

protected IActivation activation = new IActivation.S1();

查看原始代码,很清楚这是什么意思:

  1. 声明一个接口并在其中嵌套该接口的几个静态实现(该代码包含IActivation的其他实现,例如“S2”,“S3”等,这里省略了。)
  2. 这种情况的典型用法是将变量分配给该接口的一个特定实现。此外,通过您需要实例化该变量的方式,非常清楚这些特定实现所属的位置 - 从某种意义上讲,嵌套声明将进一步提高代码的可读性 (例如new IActivation.S1();表明S1是IActivation的特定实现。)
  3. 有趣的是,C#并不喜欢定义整个事物的方式:“无法创建静态类'IActivation.S1 的实例”。有没有人知道如何重构该代码以便保留1.和2.?

5 个答案:

答案 0 :(得分:11)

在Java中,static内部类对其封闭类型的成员没有隐式访问权限。在C#中,所有嵌套类型都没有对其父类型成员的访问权限;您无需在C#中添加任何修饰符来触发此行为。

在C#中,static类是abstract sealed,因此无法创建或派生它们 - 这与Java中的含义不同。另外,接口不能包含它们自己的类型声明。

尝试这样的事情:

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

如果您的目标是以某种“可读”的方式提供默认实现(尽管我认为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();
        }
    }
}

但是,我对这一说法更具可读性或更有帮助的说法提出质疑。当在特定类型的上下文中构造对象时,Visual Studio将显示该类型的所有子类型。所以如果你这样做(|代表光标):

IActivator foo = new |

您应该获得当前范围中实现IActivotor的所有类的简洁列表。

答案 1 :(得分:6)

请勿将您的课程标记为static

答案 2 :(得分:2)

错误消息本身很清楚,S1类不能是静态的,因为您正在创建它的实例。从S1中删除static关键字。此外,访问修饰符和抽象修饰符在接口声明中无效。

在C#中,接口不能声明内部类型。

我的建议是使用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 { }

答案 3 :(得分:2)

如果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;
        }
    }
}

这改变了代码的实际含义,但允许你说

var s1 = new IActivation.S1();

更新我能想到的主要问题是,如果你有一个扩展别的东西并实现这个接口的类它将无法工作(你不能从两个类继承)。然后,您可以创建一个接口和一个实现抽象类的抽象类,但这有点傻。

另一种选择是

public interface IActivation {
    // ...
}

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

优点是您将IActivation保留为接口,但是您有另一个类乱丢您的命名空间。

在这两种情况下,你都没有从Java那里做过直接端口。

答案 4 :(得分:0)

使用sigleton模式为每个S'i'实现和撕裂appart接口和实现如上所述cdhowie

看来你不需要工厂 - 除非你的S'i'实例有自己的状态?