C#: создание экземпляра абстрактного класса без определения нового класса
Я знаю, что это можно сделать на 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#, и если да, то как?
9 ответов
с выражениями 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. Если вы собираетесь голосовать ответ, сделай нам всем одолжение и добавить комментарий, почему вы не согласны :-)
метод Java называется"анонимный внутренний класс", и нет эквивалента в C#.
Как правило, проблемы, которые решаются с анонимными внутренними классами в Java, решаются гораздо более чистым способом с помощью делегатов .Сеть. Ваш пример слишком упрощен, чтобы определить ваше намерение. Если ваше намерение с помощью абстрактного класса состоит в том, чтобы передать "поведение", подумайте только об использовании делегат.
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#; вам нужно объявить новый тип класса. Ближайший вы можете получить в C# наверное имени вложенного класса:
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#, и если бы это зависело от меня это не должно быть так или.
распространение внутренних классов в java в основном связано с отсутствием делегатов или лямбд, которые имеет C#. Поэтому, хотя этот тип функциональности в настоящее время является "вашей единственной надеждой" на java, вы обычно можете использовать другие механизмы на C# для достижения тех же целей. Java чувствует, что играет на пианино одной рукой в этом отношении.
(по общему признанию, многие из нас получили довольно хорошо в этом игра одной рукой; и теперь кажется, что мы должны ждать, по крайней мере, до java 8 для закрытия...)
поскольку ваш класс представляет только действие, вы можете использовать делегат в вашем случае, есть существующий делегат:
public delegate void Action();
это точный эквивалент своего класса.
и déclaration вашего анонимного класса еще чище:
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();
}
}
вы можете сделать это с насмешкой .Сеть. Однако для этой функции нет языковой поддержки, я думаю, что она будет доступна в C# 4.0. Существует ряд библиотек для издевательств, в том числе:
короче нет, вы должны определить его как отдельный класс. Я думаю, что эта функция идет C# 4.0, хотя?
Edit: нет, это не придет C# 4.0, я это придумал.