【问题标题】:Store Static Reference to Instance Method?存储对实例方法的静态引用?
【发布时间】:2011-08-10 07:17:37
【问题描述】:

我想创建一个包含委托的静态数组。我将使用这个数组来查找我需要的委托。例如:

class HandlerID
{
    public int ID { get; set; }
    public Func<int, bool> Handler { get; set; }
}

protected const HandlerID[] HandlerIDs = {
    new SectionRenderer() { ID = SectionTypes.Type1, Handler = MyType1Handler },
    new SectionRenderer() { ID = SectionTypes.Type2, Handler = MyType2Handler },
    // Etc.
}

protected bool MyType1Handler(int arg)
{
    return false;
}

// Etc.

但是,在 HandlerID 数组中对 Handler 的赋值会出现以下错误:

非静态字段、方法或属性“MyType1Handler(int)”需要对象引用

我希望数组是const,因此不必为我的类的每个实例都初始化它。有没有办法将实例方法存储在静态数组中?

【问题讨论】:

  • 你不能创建 const 数组。
  • 那你会怎么称呼我的代码创建的?
  • 编译器错误。你的意思是创建一个static readonly 字段。
  • 这是一个很好的问题,Lippert 博客资料。失去 const 以获得一些清晰,这是 C++ 的思想。委托需要位信息、方法和目标。目标总是在 C# 中从上下文中推断出来。 C# 将拒绝从字段初始化器中推断它。有点傻,因为它已经将初始化代码移动到构造函数。它不反对推断目标。 C++/CLI 的工作方式相同,这让我有点惊讶,因为它需要显式传递目标。这是一个对象初始化顺序问题。
  • @Hans:this 关键字不可用于内联初始值设定项,这会导致此处看到的行为。在构造函数完成之前使用this 可能会很麻烦,当然使用委托是更安全的示例之一。

标签: c# delegates lambda


【解决方案1】:

这没有意义。
当您调用数组中的委托时,他们需要您的类的实例来操作。

因此,您需要为每个类实例设置一组单独的委托。

如果方法实际上不需要实例来操作,您可以将它们设为static,这样可以解决问题。

或者,您可以将实例作为委托的参数,并使用调用该方法的 lambda 表达式:Handler = (instance, arg) =&gt; instance.MyType1Handler(arg)

【讨论】:

  • 除非有某种方法可以从静态存储的信息中推断出实例委托。这就是问题所在。似乎有可能,如果没有别的,就使用反射。
  • 这没有意义。是static,所以没有实例。
  • 您可以创建开放委托并将它们存储在静态数组中,然后在调用站点提供实例。
  • 你必须像Handler = instance.MyType1Handler一样。就像 SLaks 所说,您需要一个实例来调用非静态成员。
  • @Ben:是的,但是你需要使用反射来做到这一点。 Lambda 表达式要简单得多。
【解决方案2】:

您不能在 C# 中声明 const 数组,请尝试 readonly 以确保指向数组(实例)的指针不会改变,但据我所知,没有办法以声明方式阻止元素被更改.

【讨论】:

  • @SLaks:是的,当然有办法做到这一点,我的观点是,与 C++ 中所说的不同,没有用于常量数组的 C# 语言 构造(我怀疑是作者的意图)。
【解决方案3】:

您不能为静态函数创建委托,也不能为不存在的对象实例中的函数创建委托。但是,您可以存储 MethodInfo 并稍后在实例上调用它。

 // Use MethodInfo instead of Func in HandlerId
 public MethodInfo Method { get; set; }

 // Create the static list of handlers
 protected static HandlerID[] HandlerIDs = {    
  new SectionRenderer() { ID = SectionTypes.Type1, Method = typeof(MyHandlersClass).GetMethod("MyType1Handler") },    
  new SectionRenderer() { ID = SectionTypes.Type2, Method = typeof(MyHandlersClass).GetMethod("MyType2Handler") },    
   // Etc.
  }

  // invoke at some point
  HandlersIds[0].Method.Invoke(aninstanceobject, new object[] { arg } );

【讨论】:

  • “无法创建静态函数的委托”:错误。 “无法为没有实例的函数创建委托”:错误。 MethodInfo:慢。
  • - 1/2 对我来说:“Visual Basic、C++ 或 C# 不直接支持创建打开实例和关闭静态委托的委托构造函数。相反,请使用 Delegate.CreateDelegate 之一指定 MethodInfo 对象的方法重载,例如 Delegate.CreateDelegate(Type, Object, MethodInfo, Boolean)。"
  • 没错,调用CreateDelegate 非常值得,因为调用生成的委托比使用MethodInfo.Invoke 快几个数量级。另请注意,MSDN 所说的是 C# 中没有用于使用静态方法创建封闭委托的语法。使用静态方法创建开放委托很容易,但您的回答认为这是不可能的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多