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

时间:2021-01-03 22:29:25

I know it can be done in Java, as I have used this technique quite extensively in the past. An example in Java would be shown below. (Additional question. What is this technique called? It's hard to find an example of this without a name.)

我知道它可以用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();
   }
}

Now, my main question would be, can this also be done in C#, and if so, how?

现在,我的主要问题是,这也可以在C#中完成,如果是这样,怎么样?

9 个解决方案

#1


With lamba expressions and class initializers you can get the same behaviour with a bit of effort.

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

One problem with this solution that I just realized is that if you were to create fields in the Example class, the lambda expressions would not be able to access those fields.

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

However, there is no reason that you could not pass the instance of Example to the lambda expressions which would give them access to any public state that example might hold. AFAIK that would be functionally equivalent to the Java Anonymous Inner Class.

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

P.S. If you are going to vote an answer down, do us all a favour and add a comment as to why you disagree :-)

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

#2


The Java technique is called "Anonymous inner class", and there is no equivalent in C#.

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

#3


Typically, problems that are solved with anonymous inner classes in Java are solved in a much cleaner fashion using delegates in .Net. Your example is a little too simplistic to determine your intent. If your intent by using the abstract class is to pass around a "behavior" think about just using an Action delegate instead.

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

#4


That can't be done in C#; you need to declare a new class type. The closest you can get in C# is probably a named nested class:

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

#5


This is not supported in C#, and if it were up to me it shouldn't be so either.

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

The proliferation of inner classes in java is mainly due to the lack of delegates or lambdas, which C# has. So while this type of functionality currently is "your only hope" in java, you can usually use other mechanisms in C# to achieve the same ends. Java feels like playing the piano with one hand in this regard.

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

(Admittedly a lot of us have gotten quite good at this one-handed playing; and now it seems like we have to wait at least until java 8 for closures...)

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

#6


Since your class represents only an action, you can use a delegate in your case, there is an existing delegate :

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

public delegate void Action();

This is the exact equivalent of your class.

这与您的班级完全相同。

And the déclaration of your anonymous class is even cleaner :

你的匿名课程的宣言更加清晰:

Action action = () => Console.WriteLine("Hello world");
action(); // invoke

you can even use closure :

你甚至可以使用闭包:

public void Hello(string name)
{
  Action action = () => Console.WriteLine("Hello " + name);
  action(); // will call the above lambda !
}

#7


While all good answers, most of the work arounds suggested rely on C# 3.0

虽然所有好的答案,大多数建议的工作依赖于C#3.0

So, for the sake of completeness, I'll add another solution that uses neither lambdas nor Func type (Granted that, as Matt Olenik mentioned in the comments, one could generalize the below delegates to work the same way.). For those, like me who may still be working with C# 2.0. Maybe not the best solution, but it works.

因此,为了完整起见,我将添加另一个既不使用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();
    }
}

#8


You are able to accomplish this with Mocking in .NET. However there is no in-language support for this feature, I think it will be available in C# 4.0. There are a number of libraries out there for Mocking, including:

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

#9


In short no, you have to define it as separate sub class. I think this feature is coming C# 4.0 though?

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

Edit: No it's not coming C# 4.0 I made that up.

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

#1


With lamba expressions and class initializers you can get the same behaviour with a bit of effort.

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

One problem with this solution that I just realized is that if you were to create fields in the Example class, the lambda expressions would not be able to access those fields.

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

However, there is no reason that you could not pass the instance of Example to the lambda expressions which would give them access to any public state that example might hold. AFAIK that would be functionally equivalent to the Java Anonymous Inner Class.

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

P.S. If you are going to vote an answer down, do us all a favour and add a comment as to why you disagree :-)

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

#2


The Java technique is called "Anonymous inner class", and there is no equivalent in C#.

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

#3


Typically, problems that are solved with anonymous inner classes in Java are solved in a much cleaner fashion using delegates in .Net. Your example is a little too simplistic to determine your intent. If your intent by using the abstract class is to pass around a "behavior" think about just using an Action delegate instead.

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

#4


That can't be done in C#; you need to declare a new class type. The closest you can get in C# is probably a named nested class:

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

#5


This is not supported in C#, and if it were up to me it shouldn't be so either.

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

The proliferation of inner classes in java is mainly due to the lack of delegates or lambdas, which C# has. So while this type of functionality currently is "your only hope" in java, you can usually use other mechanisms in C# to achieve the same ends. Java feels like playing the piano with one hand in this regard.

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

(Admittedly a lot of us have gotten quite good at this one-handed playing; and now it seems like we have to wait at least until java 8 for closures...)

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

#6


Since your class represents only an action, you can use a delegate in your case, there is an existing delegate :

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

public delegate void Action();

This is the exact equivalent of your class.

这与您的班级完全相同。

And the déclaration of your anonymous class is even cleaner :

你的匿名课程的宣言更加清晰:

Action action = () => Console.WriteLine("Hello world");
action(); // invoke

you can even use closure :

你甚至可以使用闭包:

public void Hello(string name)
{
  Action action = () => Console.WriteLine("Hello " + name);
  action(); // will call the above lambda !
}

#7


While all good answers, most of the work arounds suggested rely on C# 3.0

虽然所有好的答案,大多数建议的工作依赖于C#3.0

So, for the sake of completeness, I'll add another solution that uses neither lambdas nor Func type (Granted that, as Matt Olenik mentioned in the comments, one could generalize the below delegates to work the same way.). For those, like me who may still be working with C# 2.0. Maybe not the best solution, but it works.

因此,为了完整起见,我将添加另一个既不使用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();
    }
}

#8


You are able to accomplish this with Mocking in .NET. However there is no in-language support for this feature, I think it will be available in C# 4.0. There are a number of libraries out there for Mocking, including:

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

#9


In short no, you have to define it as separate sub class. I think this feature is coming C# 4.0 though?

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

Edit: No it's not coming C# 4.0 I made that up.

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