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

时间:2018-01-30 01:37:47

标签: c# lambda

堆栈追踪:

System.ArgumentException: Delegate to an instance method cannot have null 'this'.
   at System.MulticastDelegate.ThrowNullThisInDelegateToInstance()
   at APP.MainForm.mainFunctions.<>c__DisplayClass16_1.<startChecking>b__1(ValueTuple`2 config)
   at System.Linq.Enumerable.WhereArrayIterator`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at APP.MainForm.mainFunctions.<>c__DisplayClass16_0.<startChecking>b__0()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

相关代码:

if(selectedConfigNames != "NULL") {
    string[] selectedConfigNamesSplit = selectedConfigNames.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
    if(selectedConfigNames.Count() > 0) {
        List<(string, string)> selectedConfigsPre = configs.ToArray().Where(config => selectedConfigNamesSplit.Any((config.Item1).Equals)).ToList();
    }
}

正如你所看到的,一个奇怪的错误正在发生,我不完全确定它为什么会发生,所以我没有太多我可以在这里说:/

任何帮助调试都会很棒!

修改

这肯定与NullReferenceException有关,但奇怪的是,我的代码几乎不可能返回null。除非WebClient.DownloadData()(。GetString'd)能以某种方式返回null。

继承我目前的代码:

string[] selectedConfigNamesSplit = selectedConfigNames.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
if (selectedConfigNamesSplit.Count() > 0) {
    configs.ToArray().Where(config => selectedConfigNamesSplit.Any(split => ((config.Item1).Equals(split))).ToList()
}

这是更新的堆栈跟踪:

System.NullReferenceException: Object reference not set to an instance of an object.
   at APP.MainForm.mainFunctions.<>c__DisplayClass16_2.<startChecking>b__2(String split)
   at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
   at APP.MainForm.mainFunctions.<>c__DisplayClass16_1.<startChecking>b__1(ValueTuple`2 config)
   at System.Linq.Enumerable.WhereArrayIterator`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at APP.MainForm.mainFunctions.<>c__DisplayClass16_0.<startChecking>b__0()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

所以从我所看到的,“split”返回null,但那是怎么回事?正如您在第一个代码块中看到的那样,它会对.Count()进行检查并在.Split()上设置一个设置以删除空条目吗?

当然可以通过以下方式解决:

configs.ToArray()。Where(config =&gt; selectedConfigNamesSplit.Any(split =&gt;(split!= null?(config.Item1).Equals(split):false)) ).ToList()

我可以确认这甚至不起作用,那么到底是什么导致了这个“NullReferenceException”?

但我更愿意知道这个错误实际发生在哪里。

1 个答案:

答案 0 :(得分:2)

从调用堆栈中,我们可以看到代码进入.Where()子句并且从未出现过。对代码的快速扫描显示,这种情况发生的唯一方法是configs中的元素为空或具有空Item1

我建议在此之前添加一些代码并检查是否是这种情况,例如

for ( int i = 0 ; i < configs.Count() ; ++i )
{
    if ( configs[i] == null) || )
    {
        WriteMessageToLog("configs element {0} was null.", i);
    }
    else if ( config[i].Item1 == null )
    {
        WriteMessageToLog("configs element {0} has a null Item1.", i);
    }
}

至于语法,我可以看到为什么有些人会对你选择的构造有问题,但它完全有效。

selectedConfigNamesSplit.Any(config.Item1.Equals)
// ... is equivalent to ...
selectedConfigNamesSplit.Any(c => config.Item1.Equals(c))

lambda和Equals方法组本身都是接受单个参数的委托,将其与字符串进行比较,并返回布尔结果。虽然我对此没有任何问题,但有些人可能会质疑此代码的可读性,但这是由您的特定组织的编码标准决定的。

还有一点,第二个if子句正在检查selectedConfigNames.Count()。我很确定你不是故意这样做的。 这会将selectedConfigNames字符串视为IEnumerable<char>,然后使用Linq计算字符串中的字符数。我认为你打算做selectedConfigNamesSplit.Length来测试数组是否包含任何项目。

修改

我使用以下代码重现了您所遇到的错误:

var configs = new Tuple<string, object>[] { new Tuple<string, object>( null, null) };
var selectedConfigNamesSplit = new [] { "A", "B", "C", "D" };
configs.Where(config => selectedConfigNamesSplit.Any(config.Item1.Equals)).ToList();

这会抛出原始的System.ArgumentException: Delegate to an instance method cannot have null 'this'.

但是,将configs中的Item1值更改为非空值时,错误就会消失。

var configs = new Tuple<string, object>[] { new Tuple<string, object>("D", null) };
var selectedConfigNamesSplit = new [] { "A", "B", "C", "D" };
configs.Where(config => selectedConfigNamesSplit.Any(config.Item1.Equals)).ToList();

所以我要回到原来的

陈述
  

configs中的元素为null或config.Item1为null

希望这有帮助