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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/515876/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 06:25:29  来源:igfitidea点击:

C#: Creating an instance of an abstract class without defining new class

c#abstract-classabstractanonymous-class

提问by vipirtti

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# 中完成,如果可以,怎么做?

采纳答案by Darrel Miller

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.

但是,没有理由不能将 Example 的实例传递给 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 :-)

PS如果您要投票否决答案,请帮我们一个忙并添加评论以说明您不同意的原因:-)

回答by Anton Gogolev

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

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

回答by Marc Gravell

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

回答by Chris S

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 我编造的。

回答by Nick Berardi

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:

您可以使用 .NET 中的 Mocking 来完成此操作。但是,此功能没有语言支持,我认为它会在 C# 4.0 中可用。有许多用于 Mocking 的库,包括:

回答by krosenvold

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# 所具有的委托或 lambda。因此,虽然目前在 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 才能关闭......)

回答by Michael Meadows

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 Actiondelegate instead.

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

回答by vipirtti

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

回答by thinkbeforecoding

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