0

Stack Trace:

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()

Related Code:

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

As you can see, a strange error is occuring, im not fully sure why its occuring either so I dont have much that I can really say here :/

Any help debugging would be great!


EDIT

It's definitely to do with a NullReferenceException but the strange thing is, it is almost impossible for my code to return a null. Unless WebClient.DownloadData() (.GetString'd) can somehow return a null.

Heres my current code:

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

And here's the updated stack trace:

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()

So from what I can see, "split" is returning null, but how is that? As you can see in the first code block, it does .Count() checks and has a setting on .Split() to remove empty entries?

It can of course be resolved by doing:

configs.ToArray().Where(config => selectedConfigNamesSplit.Any(split => (split != null ? (config.Item1).Equals(split) : false))).ToList()

I can confirm this doesnt even work, so what the hell is causing this "NullReferenceException"?

But i'd prefer to be able to know where this error is actually occurring.

  • this is where the exveption is being thrown http://referencesource.microsoft.com/#mscorlib/system/multicastdelegate.cs,4a74b2f22c432eda,references – pm100 Jan 30 '18 at 01:44
  • I would split this line up `List<(string, string)> selectedConfigsPre = configs.ToArray().Where(config => selectedConfigNamesSplit.Any((config.Item1).Equals)).ToList();` into separate variables which will make stepping through with breakpoints much easier. You can also run statements in the immediate window when you're stopped at a breakpoint although LINQ sometimes protests. – Matt Stannett Jan 30 '18 at 01:44
  • 1
    In your first `if` condition, you realize you're comparing to a string literal and not checking for `null`, right? – Rufus L Jan 30 '18 at 01:46
  • In your second `if` statement, do you mean to be checking `selectedConfigNamesSplit` instead of `selectedConfigNames`? – Rufus L Jan 30 '18 at 01:47
  • `(config.Item1).Equals)` equals what? what do you think you are comparing against? – pm100 Jan 30 '18 at 01:49
  • @RufusL I do, thats intentional, it sends a literal string saying NULL when theres no "confignames". Yes I do actually, I edited that. The thing is this doesnt happen at all to me, but does to my users. Which is where I have the stack traces from. –  Jan 30 '18 at 01:49
  • @pm100 I got that bit of code from a page here on stack, seems to work fine on my end. Its comparing "config" 's first item with each item in the split array. –  Jan 30 '18 at 01:50
  • I don't recognise this syntax, but I would suggest that the only place a null reference could creep in is either an element in `configs` is null or a `config.Item1` is null. Possibly add some extra logging before this code that tests for both conditions. – Trevor Jan 30 '18 at 01:53
  • `List<(string, string)>` doesn't compile on my machine. is that some fancy C#7 syntax? – Rufus L Jan 30 '18 at 01:54
  • @RufusL: yes, that's the new tuple syntax, shorthand for `List>`. – Peter Duniho Jan 30 '18 at 01:58
  • @pm100 That syntax is short for: `Any(c => (config.Item1).Equals(c)))` – Rufus L Jan 30 '18 at 01:58
  • You need to provide a good [mcve] that reliably reproduces the problem. It is strange indeed that the delegate's target object would be null, and it could be a bug (e.g. in the compiler), but there's no way to know from the teensy tiny little bit of code you've offered here what could be causing that, never mind how to fix it. – Peter Duniho Jan 30 '18 at 02:00
  • Agreed, the snippet of code you've presented works fine for me when I populate the items (`selectedConfigNames` and `configs`) with reasonable data. – Rufus L Jan 30 '18 at 02:08
  • ", thats intentional, it sends a literal string saying NULL when theres no "confignames"" - It's a good idea to never do things like this where the intent isn't obvious. Like calling `Equals` when you're not actually comparing it to anything. No one reading that would ever be able to guess why you were doing that. – Scott Hannen Jan 30 '18 at 02:09
  • @ScottHannen No one *who doesn't use ReSharper*, you mean. By default ReSharper will suggest converting `.Any(c => (config.Item1).Equals(c)))` to `.Any((config.Item1).Equals)`. I believe it's called "method group" syntax. :) – Rufus L Jan 30 '18 at 02:10
  • @RufusL I use resharper too - "convert to method group." I meant using `Equals` as a null check. – Scott Hannen Jan 30 '18 at 02:34
  • Possible duplicate of [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – ProgrammingLlama Jan 31 '18 at 02:10
  • I've flagged as a duplicate because it is. Trevor's more detailed answer re your specific scenario is correct. Inspect your `configs` array using the debugger. – ProgrammingLlama Jan 31 '18 at 02:11

1 Answers1

2

From the call stack, we can see that the code went into the .Where() clause and never came out. A quick scan of the code reveals that the only way this can happen is if an element in configs is null or has a null Item1.

I'd recommend adding some code to run before this and check to see if this is the case, something like

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

As for the syntax, I can see why some people would have trouble with your choice of construct, but it is perfectly valid.

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

Both the lambda and the Equals method group itself itself are delegates that accept a single parameter, compare that to the string, and return a boolean result. While I have no problem with this, some people might question the readability of this code, but that is for your particular organisation's Coding Standards to decide.

One more note, your second if clause is checking selectedConfigNames.Count(). I'm pretty sure you didn't mean to do this. This will consider the selectedConfigNames string as an IEnumerable<char> and will then count the characters in the string using Linq. I think you meant to do selectedConfigNamesSplit.Length to test to see if the array contained any items.

Edit

I've reproduced the error you are having with the following code:

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();

This throws the original System.ArgumentException: Delegate to an instance method cannot have null 'this'.

However, changing the Item1 value in configs to a non-null value, the error goes away.

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();

So I'm going to go back to my original statement of

either an element in configs is null or a config.Item1 is null

Hope this helps

Trevor
  • 1,251
  • 1
  • 9
  • 11
  • It seems to definitely be a null issue but surprisingly on the split.Any() instead o.o See updated question. –  Jan 30 '18 at 17:15
  • I don't think that `split` is returning null, and the fact that changing the delegate inside the `Any()` to a lambda function has changed the stack trace makes me think even more that the problem is a null element in `configs` or an element in `configs` having a null `Item1`. Can you post the code which creates / validates `configs`? – Trevor Jan 30 '18 at 17:26
  • You might be right, I can confirm my null check within the Where doesnt work. –  Jan 31 '18 at 01:54
  • Btw the actual "config" item CANNOT be null due to it being a tuple. Apparently it cant be null at all says IDE. So it has to be either Item1 or Item2 –  Jan 31 '18 at 02:19
  • @user8549339 I've reproduced your problem and tested the fix I suggested. I've edited the answer to include both. – Trevor Feb 01 '18 at 10:11