【问题标题】:why does a function that added to delegate needs to be static?为什么添加到委托的函数必须是静态的?
【发布时间】:2012-03-21 12:58:18
【问题描述】:

我声明了一个委托:

public delegate void Del(string message);

然后我创建了一个要添加到委托的函数:

public static void DelegateMethod(string message)
{
    System.Console.WriteLine(message);
}

现在我将函数添加到委托并调用它:

Del handler = new Del( DelegateMethod);
handler("Hello World");
Console.Read();

为什么当我从 DelegateMethod 中删除 static 时会出现错误?

为什么我委托的函数必须是静态的?

【问题讨论】:

  • 您要添加处理程序的函数在什么范围内?
  • 也许您正在从静态类/函数中调用代码?我认为这是 VS 中控制台应用程序的默认设置(您的 Main 函数将是静态的)。非静态函数只有在你有一个包含它们的类的实例时才能访问,而你没有
  • @musefan - 谢谢,我没有注意到我在控制台主要静态方法中。

标签: c# methods delegates


【解决方案1】:

为什么当我从 DelegateMethod 中删除“静态”时会出现错误?

因为您是在静态方法中编写此代码。鉴于您使用的是Console.Read,我假设您已将此代码放入控制台应用程序的static void Main 方法中。如果您想删除该方法中的static 关键字,您将需要一个包含该方法的类的实例。像这样:

class Program
{
    public delegate void Del(string message);

    public void DelegateMethod(string message)
    {
        System.Console.WriteLine(message);
    }

    static void Main()
    {
        Del handler = new Del(new Program().DelegateMethod);
        handler("Hello World");
        Console.Read();
    }
}

【讨论】:

    【解决方案2】:

    为什么当我从 DelegateMethod 中删除“静态”时会出现错误?

    您没有具体说明您感到困惑的错误。我怀疑您感到困惑的错误是,如果 DelegateMethod 不是 static 并且您正在包含类中的 static 方法中编写代码行,则该行将无法编译:

    Del handler = new Del( DelegateMethod); 
    

    这样做的原因是因为如果你不将DelegateMethod声明为static,那么你需要一个实例来引用该方法。鉴于您的代码可能是在包含类的static 方法中编写的,因此没有隐式this,因此您需要一个显式实例。假设您的包含类名为 Foo:

    Foo foo = new Foo();
    Del handler = ne Del(foo.DelegateMethod);
    

    看到了吗?

    【讨论】:

    • 但也有可能是代码位于静态方法内部,因此只能访问其他静态方法。看到了吗?
    • 您没有仔细阅读我的回答吗?我谈到了这一点。
    【解决方案3】:

    您误认为委托需要使用静态方法。

    方法签名(返回类型和参数 - 类型、数量和顺序)需要与委托匹配才能与之兼容。

    来自 MSDN - Delegates (C# Programming Guide):

    任何可访问类或结构中与委托签名匹配的任何方法(包括返回类型和参数)都可以分配给委托。 方法可以是静态方法或实例方法

    (强调我的)


    当使用 instance 方法作为委托目标时,您必须引用一个实际的实例:

    public class MyClass
    {
        public static void DelegateMethod(string message)
        {
            System.Console.WriteLine(message);
        }
    }
    
    var myClass = new MyClass();
    Del handler = new Del(myClass.DelegateMethod);
    

    【讨论】:

    • 看起来 Jason 在这里大肆投票,因为他不明白我们要解释的内容。
    • @ØyvindKnobloch-Bråthen - 不,我明白他的意思,尽管他确实对反对票感到满意。
    • 但是代码可能位于静态方法中这一事实并没有错,只是它不是唯一的选择。
    • @ØyvindKnobloch-Bråthen - 是的,但事实是,如果方法不是静态的,则必须使用类的 instance 进行注册。我相信这就是问题所在。
    【解决方案4】:

    它不需要是静态的,但非静态方法需要一个实例。这就是非静态(实例)方法的定义。您可以像这样将实例方法(和实例)传递给委托:

    Del handler = new Del(instanceVariable.DelegateMethod);
    

    您可以将实例方法添加到同一类的其他实例方法中的委托。假设实例是this。

    请记住,通过这种方式,只要委托实例存在,实例就没有资格进行 GC。这有时是对象泄漏的一个原因(有些人称它们为内存泄漏,尽管泄漏在更高级别并且与 C 样式的内存泄漏不同)

    【讨论】:

    • 对不起,我错过了。要么什么?
    • 你说:“它需要一个实例”。它没有。它可以是实例方法静态方法。
    • 哦,我的意思是非静态方法需要一个实例。我以为很清楚。我会澄清的。
    【解决方案5】:

    这里只是猜测。是否包含此代码的方法:

    Del handler = new Del( DelegateMethod);
    handler("Hello World");
    Console.Read();
    

    也是静态的?在这种情况下,DelegateMethod 也必须是静态的,因为您不能从静态方法中引用非静态方法。

    【讨论】:

    • 不正确。他可以明确引用包含类的实例。
    • 这与您的回答一样可能是正确的。例如,上面的代码可能会放在控制台应用程序的 main 方法中。但是,嘿,谢谢你的反对。
    • @yvind :谢谢,我不知道谁投了反对票,但你也有正确的答案,谢谢。
    • @Øyvind Knobloch-Bråthen:我不是在谈论你的猜测。我说的是这种说法:“你不能从静态方法中引用非静态方法。”简单明了,这是错误的。 class F { void M() { } static void N() { var f = new F(); f.M(); } } 是完全合法的代码。在这里,我们有一个静态方法访问一个非静态方法。
    • Jason 不正确,您有一个访问对象成员的静态方法。该成员可能是也可能不是方法(在这种情况下是方法,但您无法从调用站点看到),并且原始代码不是访问对象的成员,而是访问代码所在类的成员。在这种情况下,该陈述是正确的
    猜你喜欢
    • 2012-04-11
    • 1970-01-01
    • 2014-05-27
    • 1970-01-01
    • 2011-06-30
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 1970-01-01
    相关资源
    最近更新 更多