委托实例方法不能为null'this'

时间:2012-12-21 05:59:43

标签: c# constructor delegates action

假设我有一个声明如下的类:

public class ExampleClass 
{
   public Action<int> Do { get; set; }

   public ExampleClass()
   {
   }

   public void FuncA(int n)
   {
       //irrelevant code here
   }

   public void FuncB(int n)
   {
       //other irrelevant code here
   }
}

我希望能够像这样使用这个类

ExampleClass excl = new ExampleClass() { Do = FuncA }

ExampleClass excl = new ExampleClass() { Do = excl.FuncA }

ExampleClass excl = new ExampleClass() { Do = ExampleClass.FuncA }

我可以在那里编译第二个选项,但是当我点击该代码时,我得到"Delegate to an instance method cannot have null 'this'."异常。第三个甚至没有意义,因为FuncA不是静态的。

在我的实际代码中,可能有10-15种不同的功能可以绑定,我可以随时添加或删除它们,所以我不想要有一个大的开关或它 - 声明。另外,在实例化类时能够为'Do'赋值是非常方便的。

我只是使用不正确的语法?有没有更好的方法来创建一个类并在一行中分配一个动作?我应该只管理并管理一个巨大的转换声明吗?

3 个答案:

答案 0 :(得分:3)

您必须创建该类的实例,然后将该属性设置为实例成员。类似的东西:

ExampleClass excl = new ExampleClass();
excl.Do = excl.FuncA;

对于你的专栏:

ExampleClass excl = new ExampleClass() { Do = FuncA }

没有该类的实例,FuncA不可见。

有关:

ExampleClass excl = new ExampleClass() { Do = excl.FuncA }

尚未创建实例,这就是您获得null引用的异常的原因。

有关:

ExampleClass excl = new ExampleClass() { Do = ExampleClass.FuncA }

FuncA不是静态方法,您无法使用类名访问它。

答案 1 :(得分:2)

在对象初始值设定项语法中,您无法在明确赋值之前访问正在初始化的变量:

ExampleClass excl = new ExampleClass() 
{ 
    Do = excl.FuncA //excl is unavailable here
}

阅读Object and Collection Initializers (C# Programming Guide)了解详情。


您可以执行以下操作,例如:

public class ExampleClass
{
    public Action<int> Do { get; set; }

    public ExampleClass(bool useA)
    {
        if (useA)
            Do = FuncA;
        else
            Do = FuncB;
    }

    public void FuncA(int n)
    {
        //irrelevant code here
    }

    public void FuncB(int n)
    {
        //other irrelevant code here
    }

}

并使用它:

 ExampleClass exclA = new ExampleClass(true);
 ExampleClass exclB = new ExampleClass(false);

另一个想法是,如果这些函数可以声明为static(即它们不需要ExampleClass的任何实例成员),那么这将起作用:

public class ExampleClass
{
    public Action<int> Do { get; set; }

    public ExampleClass() { }

    public static void FuncA(int n) { /*...*/}

    public static void FuncB(int n) { /*...*/}
}

并按照您想要的方式使用它:

ExampleClass excl = new ExampleClass() { Do = ExampleClass.FuncA };

答案 2 :(得分:0)

如果您有扩展方法,请确保在调用扩展方法之前这些值不为null,或者在扩展方法中处理空值。

例如

public static ExtensionClass 
{ 
    public static bool RunExtensionMethod(this object myObject)
    { 
        var someExecutionOnMyObject = myObject.IsValid();
        //the above line would invoke the exception when myObject is null
        return someExecutionOnMyObject ;
    }
}

public void CallingMethod()
{
    var myObject = getMyObject();

    if(myObject.RunExtensionMethod()) //This would cause "delete to an instance method cannot have null" if myObject is null
    {

    }
}

要处理此场景,如果您拥有扩展类,则处理nulls并断言null。

public static ExtensionClass 
{ 
    public static bool RunExtensionMethod(this object myObject)
    { 
         if(myObject == null) throw new ArgumentNullException(nameof(myObject));

        var someExecutionOnMyObject = myObject.IsValid();
        return someExecutionOnMyObject ;
    }
}

public void CallingMethod()
{
    var myObject = getMyObject();

    if(myObject != null && myObject.RunExtensionMethod())
    {

    }
}