C #: «Не удается создать экземпляр статического класса» - PullRequest
4 голосов
/ 22 августа 2011

Я в процессе преобразования некоторого кода 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).

Интересно, что C # не нравится, как все это определяется: " Невозможно создать экземпляр статического класса 'IActivation.S1 ". Кто-нибудь знает, как реорганизовать этот код, чтобы сохранить 1. и 2.?

Ответы [ 5 ]

11 голосов
/ 22 августа 2011

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

6 голосов
/ 22 августа 2011

Не отмечайте свой класс как static.

2 голосов
/ 22 августа 2011

Если 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.

2 голосов
/ 22 августа 2011

Само сообщение об ошибке ясно, класс 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 голосов
/ 22 августа 2011

использовать шаблон сиглета для каждой реализации S'i 'и разрывать интерфейс и реализацию appart, как описано выше cdhowie

Кажется, вам не нужна фабрика - разве ваши экземпляры S'i' имеют собственное состояние?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...