Intereting Posts
Получить услугу в расширении IServiceCollection Как я могу вернуть один элемент за раз с каждой кнопкой? Создайте сопрограмму для выведения различных типов объектов System.InvalidCastException при создании объекта, активированного клиентом, с использованием более старой версии интерфейса, определенного в сильной именованной сборке Readonly ComboBox в WinForms Предложите метод автоматического обновления моей программы на C # Где я могу найти профилировщик для приложений C #, которые будут использоваться в Visual Studio 2008? Когда мы используем ANTLR Вызов команды из кода ASP .Net: проблема с уникальной электронной почтой AspNetSqlMembershipProvider Загрузка FTP-сервера FtpWebRequest с помощью ProgressBar Валидация аннотаций пользовательских данных на стороне клиента помощь с Regex – требуется до 3 чисел после точки (.) Почему после проверки не будет отправлено мое сообщение? C # generics: упростить подпись типа

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

Я знаю, что это можно сделать на 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(); } } 

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

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

     public class Example { public Action DoStuff; public Action DoStuffWithParameter; public Func 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(); } } 

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

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

    PS Если вы собираетесь проголосовать за ответ, сделайте нам все одолжение и добавьте комментарий о том, почему вы не согласны 🙂

    Метод Java называется « Анонимный внутренний class », и на C # нет эквивалента.

    Как правило, проблемы, которые решаются с анонимными внутренними classами Java, решаются гораздо более чистым способом с использованием делегатов в .NET. Ваш пример слишком упрощен, чтобы определить ваши намерения. Если ваше намерение с помощью абстрактного classа состоит в том, чтобы обойти «поведение», подумайте только об использовании делегата 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(); } } 

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

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

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

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

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

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

     public delegate void Action(); 

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

    И оформление вашего анонимного classа еще чище:

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

    В то время как все хорошие ответы, большая часть работы вокруг полагается на C # 3.0

    Итак, ради полноты, я добавлю другое решение, которое не использует ни типы lambdas, ни Func (признал, что, как отметил Мэтт Оленик в комментариях, можно было бы обобщить нижеперечисленных делегатов на работу одинаково). Для тех, как я, которые все еще могут работать с C # 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(); } } 

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

    • Moq
    • RhinoMock

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

    Редактировать: Нет, это не придет C # 4.0. Я сделал это.