2011-08-22 428 views
4

我在一些Java代码转换为C#的过程中,遇到下列奇怪的事情偶然发现: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. 声明的接口和嵌套了好静我内该接口的实现(该代码包含IA激活的其他实现,例如, “S2”,“S3”等在此省略)。
  2. 这种典型的使用场景是将变量分配给该接口的一个特定实现。另外,按照您需要实例化该变量的方式,可以很清楚地了解这些特定实现属于哪个位置 - 以某种方式说,嵌套声明将进一步提高代码的可读性(例如new IActivation.S1();明确指出S1是IA激活的具体实现)。

有趣的是,C#不喜欢整个事情的定义方式:“无法创建静态类“IActivation.S1的实例”。有没有人知道如何重构该代码的方法,以便1.和2.会被保留下来?

+0

为什么你需要将类声明为静态? – Morvader

+0

@Morvader:当应用于类时,'static'在Java中的含义与C#中的含义不同。 – cdhowie

+0

新增了[标签:java的],它希望将吸引的人谁知道Java的... – AakashM

回答

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直接端口。

+0

好主意!使用这种将接口转换为抽象类的方式时是否有任何缺点/副作用?也就是说,与接口声明相比,有什么我无法完成的吗? – MrCC

+0

我已经用另一个可能的解决方案更新了答案 –

+0

无论如何,从Java到C#的100%端口是不可能的(在我的情况下),所以我不关心这个问题(例如,在方法声明中没有“抛出” C#)。解决方案1唯一的缺点是你没有“实现接口”智能感知功能(多继承问题很容易通过“查找所有引用”进行验证,并且在我的情况下不存在)。我也很好奇这个“覆盖”是否对性能有任何负面影响(不应该有)。第二种解决方案基本上使用了与1相同的技术(即:C#中的嵌套类都可以,而不是接口类混合)。 – MrCC

6

不要将您的课程标记为static

+0

这本身就不会做,不幸的是,你会得到一个_'S1的答案:当您尝试接口不能声明types_错误。我认为它归结为Bas和cdhowie(详见下文):“在C#中,接口不能声明内部类型。” – MrCC

+0

我只回答“无法创建静态类的实例”。我建议OP读取编译器错误,C#编译器生成详细的错误描述。 –

+2

好吧,我问了一个你没有回答的具体问题。另外,你的“答案”导致进一步的不可编译的代码,所以我没有看到这一点。 – MrCC

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类的整齐的列表。

+0

的确,这是我考虑过的可能性之一,但它会打破“代码可读性”约束(第2点)。因为那么你必须使用'protected IActivation activation = new S1();'。最初的意图(这是我的猜想,因为代码不是来自我的)是有某种形式的智能感知为您提供替代方案,如果您觉得必须使用其他实现。在你的情况下,每个人都必须猜测其他实现是什么...... – MrCC

+0

我看到你已经在我的第一条评论后更新了你的答案,非常感谢。也许我应该澄清一点:在原始程序员的设计中,“IA激活激活=新IA激活。”将列出IA激活的所有可用实现,而不是其他(例如IActivation2的实现)。为了达到同样的效果,你需要使用一个工厂模式,这是相当高的写入空间。没有冒犯的意思,但我目前认为约翰的解决方案是最合适的解决方案,尽管存在缺陷(项目中不存在这些缺陷)。 – MrCC

2

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

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

我在这里的建议是使用工厂模式来获取正确的情况下,而不是嵌套类型的接口(这会增加耦合/依赖)。

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 { } 
0

每个S'i使用sigleton模式“的实施和撕裂由cdhowie上述APPART接口和实现

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