C#:在不定义新类的情况下创建抽象类的实例

时间:2009-02-05 13:25:36

标签: c# abstract-class abstract anonymous-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#中完成,如果是的话,怎么做?

9 个答案:

答案 0 :(得分:21)

Java技术称为“Anonymous inner class”,C#中没有等效技术。

答案 1 :(得分:17)

使用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类中创建字段,lambda表达式将无法访问这些字段。

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

P.S。如果你要投票给答案,请帮我们一个忙,并添加评论,说明你不同意的原因: - )

答案 2 :(得分:10)

通常,使用.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();
   }
}

答案 3 :(得分:8)

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

答案 4 :(得分:1)

这在C#中是不受支持的,如果它由我决定也不应该如此。

java中内部类的增加主要是由于缺少C#所具有的委托或lambdas。因此,虽然这种类型的功能目前是java中的“唯一希望”,但您通常可以在C#中使用其他机制来实现相同的目的。在这方面,Java就像用一只手弹钢琴一样。

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

答案 5 :(得分:1)

虽然所有答案都很好,但大多数建议依赖于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();
    }
}

答案 6 :(得分:1)

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

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

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

你可以通过Mocking in .NET来实现这一目标。但是,对于此功能没有语言支持,我认为它将在C#4.0中提供。 Mocking有很多图书馆,包括: