С#: создание экземпляра абстрактного класса без определения нового класса
Я знаю, что это можно сделать на 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();
}
}
Теперь, мой главный вопрос: может ли это также быть сделано на С#, и если да, то как?
Ответы
Ответ 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. Если вы собираетесь проголосовать за ответ, сделайте нам все одолжение и добавьте комментарий о том, почему вы не согласны: -)
Ответ 2
Технология Java называется " Анонимный внутренний класс", и на С# нет эквивалента.
Ответ 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, в том числе: