Подтвердить что ты не робот

С#: создание экземпляра абстрактного класса без определения нового класса

Я знаю, что это можно сделать на Java, поскольку я использовал этот метод довольно широко в прошлом. Пример в Java будет показан ниже. (Дополнительный вопрос: что называется этим методом? Невозможно найти пример этого без имени.)

public abstract class Example {
   public abstract void doStuff();
}

public class StartHere{
   public static void main(string[] args){
      Example x = new Example(){
         public void doStuff(){
            System.out.println("Did stuff");
         }            
      };
      x.doStuff();
   }
}

Теперь, мой главный вопрос: может ли это также быть сделано на С#, и если да, то как?

4b9b3361

Ответ 1

С выражениями lamba и инициализаторами классов вы можете получить такое же поведение с небольшим усилием.

public class Example {
    public Action DoStuff;
    public Action<int> DoStuffWithParameter;
    public Func<int> DoStuffWithReturnValue;
}

class Program {
    static void Main(string[] args) {
        var x = new Example() {
            DoStuff = () => {
                Console.WriteLine("Did Stuff");
            },
            DoStuffWithParameter = (p) => {
                Console.WriteLine("Did Stuff with parameter " + p);
            },
            DoStuffWithReturnValue = () => { return 99; }


        };

        x.DoStuff();
        x.DoStuffWithParameter(10);
        int value = x.DoStuffWithReturnValue();
        Console.WriteLine("Return value " + value);
        Console.ReadLine();
    }
}

Одна проблема с этим решением, которое я только что понял, заключается в том, что если вы должны создавать поля в классе Example, выражения лямбда не смогут получить доступ к этим полям.

Однако нет причин, по которым вы не могли бы передать экземпляр Example в лямбда-выражения, которые предоставили бы им доступ к любому публичному состоянию, которое может содержать пример. AFAIK, который будет функционально эквивалентен явному внутреннему классу Java.

P.S. Если вы собираетесь проголосовать за ответ, сделайте нам все одолжение и добавьте комментарий о том, почему вы не согласны: -)

Ответ 3

Как правило, проблемы, которые решаются с анонимными внутренними классами Java, решаются гораздо более чистым способом с использованием делегатов в .NET. Ваш пример слишком упрощен, чтобы определить ваши намерения. Если ваше намерение с помощью абстрактного класса состоит в том, чтобы обойти "поведение", подумайте только об использовании делегата Action.

public class StartHere{
   public static void main(string[] args){
      Action doStuff = () => Console.WriteLine("Did stuff");
      executeSomething(doStuff);
   }

   public static void executeSomething(Action action)
   {
      action();
   }
}

Ответ 4

Это невозможно сделать в С#; вам нужно объявить новый тип класса. Ближе всего вы можете попасть в С#, возможно, это вложенный класс:

public class StartHere{
    private class Foo : Example {
        public override void  doStuff()
        {
            Console.WriteLine("did stuff");
        }
    }
   public static void Main(string[] args){
      Example x = new Foo();
      x.doStuff();
   }
}

Ответ 5

Это не поддерживается в С#, и если это зависит от меня, это тоже не должно быть.

Распространение внутренних классов в java происходит главным образом из-за отсутствия делегатов или лямбда, которые имеет С#. Таким образом, хотя этот тип функциональности в настоящее время является "вашей единственной надеждой" в java, вы можете использовать другие механизмы в С# для достижения тех же целей. Java чувствует, как играть на пианино одной рукой в ​​этом отношении.

(По общему признанию, многие из нас неплохо справились с этой однорукой игрой, и теперь кажется, что нам нужно ждать хотя бы до java 8 для закрытия...)

Ответ 6

В то время как все хорошие ответы, большинство предлагаемых решений полагаются на С# 3.0

Итак, для полноты я добавлю другое решение, в котором не используются ни типы lambdas, ни Func (что, как отметил Мэтт Оленик в комментариях, можно было бы обобщить нижеперечисленных делегатов на работу одинаково). Для тех, как я, которые все еще могут работать с С# 2.0. Возможно, это не лучшее решение, но оно работает.

public class Example
{
    public delegate void DoStuffDelecate();
    public DoStuffDelecate DoStuff;
    public delegate void DoStuffWithDelecate(int n);
    public DoStuffWithDelecate DoStuffWithParameter;
    public delegate int DoStuffWithReturnDelecate();
    public DoStuffWithReturnDelecate DoStuffWithReturnValue;
}

class Program
{
    static int MethodWithReturnValue()
    {
        return 99;
    }
    static void MethodForDelecate()
    {
        Console.WriteLine("Did Stuff");
    }
    static void MethodForDelecate(int n)
    {
        Console.WriteLine("Did Stuff with parameter " + n);
    }


    static void Main(string[] args)
    {
        var x = new Example();
        x.DoStuff = MethodForDelecate;
        x.DoStuffWithParameter = MethodForDelecate;
        x.DoStuffWithReturnValue = MethodWithReturnValue;

        x.DoStuff();
        x.DoStuffWithParameter(10);
        int value = x.DoStuffWithReturnValue();
        Console.WriteLine("Return value " + value);
        Console.ReadLine();
    }
}

Ответ 7

Поскольку ваш класс представляет только действие, вы можете использовать делегат в своем случае, существует существующий делегат:

public delegate void Action();

Это точный эквивалент вашего класса.

И оформление вашего анонимного класса еще более чистое:

Action action = () => Console.WriteLine("Hello world");
action(); // invoke

вы даже можете использовать закрытие:

public void Hello(string name)
{
  Action action = () => Console.WriteLine("Hello " + name);
  action(); // will call the above lambda !
}

Ответ 8

Короче нет, вы должны определить его как отдельный подкласс. Я думаю, что эта функция подходит С# 4.0, хотя?

Изменить: Нет, не идет С# 4.0. Я это сделал.

Ответ 9

Вы можете выполнить это с помощью Mocking в .NET. Однако для этой функции нет поддержки на языке, я думаю, что она будет доступна на С# 4.0. Существует несколько библиотек для Mocking, в том числе: