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

本文关键字:this null 不能 实例方法 | 更新日期: 2023-09-27 17:49:20

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

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个不同的函数,我可以随时添加或删除它们,所以我不想有一个大的switch或it-else语句。此外,能够在实例化类时为"Do"赋值是非常方便的。

我只是使用了错误的语法吗?有没有更好的方法来创建一个类并在一行中分配一个动作?我应该像个男人一样处理一个巨大的开关声明吗?

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

您必须创建类的实例,然后将属性设置为实例成员。比如:

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

你的台词:

ExampleClass excl = new ExampleClass() { Do = FuncA }
如果没有类的实例,

FuncA是不可见的。

为:

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

实例还没有被创建,这就是为什么你得到空引用的异常。

为:

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

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

在对象初始化语法中,在确定赋值之前不能访问被初始化的变量:

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

阅读对象和集合初始化器(c#编程指南)获取更多信息。


你可以这样做,例如:

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

如果您有扩展方法,请确保在调用扩展方法或在扩展方法中处理null之前这些值不是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
    {
    }
}

要处理此场景,如果您拥有扩展类,则处理null并断言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())
    {
    }
}