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#中完成,如果是这样,怎么样?

使用lamba表达式和类初始值设定项,您可以通过一些努力获得相同的行为。

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

我刚刚意识到这个解决方案的一个问题是,如果要在Example类中创建字段,lambda表达式将无法访问这些字段。

但是,没有理由不能将示例实例传递给lambda表达式,这将使它们可以访问示例可能包含的任何公共状态。 AFAIK在function上等同于Java匿名内部类。

PS如果你打算回答一下,请帮我们一个忙,并添加评论,说明为什么你不同意:-)

Java技术被称为“ 匿名内部类 ”,在C#中没有等价物。

通常,使用.Net中的委托以更清晰的方式解决使用Java中的匿名内部类解决的问题。 您的示例有点过于简单,无法确定您的意图。 如果您使用抽象类的意图是传递“行为”,那么请考虑仅使用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#中完成; 你需要声明一个新的类类型。 你可以在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#所具有的委托或lambdas。 因此,虽然这种类型的function目前是java中的“唯一希望”,但您通常可以在C#中使用其他机制来实现相同的目的。 在这方面,Java就像用一只手弹钢琴一样。

(不可否认,我们很多人都非常擅长这种单手游戏;现在好像我们必须至少等到java 8才能关闭……)

由于您的类只代表一个操作,您可以在您的情况下使用委托,有一个现有的委托:

 public delegate void Action(); 

这与您的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类型的解决方案(当然,正如Matt Olenik在评论中提到的那样,可以概括下面的代表以相同的方式工作。)。 对于那些可能仍在使用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 in .NET来实现这一目标。 但是,对于此function没有语言支持,我认为它将在C#4.0中提供。 Mocking有很多图书馆,包括:

  • 起订量
  • RhinoMock

简而言之,您必须将其定义为单独的子类。 我认为这个function即将推出C#4.0?

编辑:不,它不会来C#4.0我做到了。