C# lambda null runtime binding - c#

I'm running into an odd scenario that doesn't happen on my PC, but does for a coworkers.
I have this piece of code:
LoaderHelpers.SetStringValue<blah>(this, "x", $"x response in Header",
() => jsonData.x.response[0].value, false);
The problem is that sometimes, "jsonData.x" is null and, for my coworker a 'cannot bind to null at runtime exception' is thrown, but not for me there isn't. I have code to handle the null scenario, but it's like his code never gets to that point and fails at the call level.
jsonData is of type dynamic.
The method code that handles the null scenario:
public static void SetStringValue<T>(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if (data.GetType().GetProperty(propertyName) != null)
{
try
{
if (string.IsNullOrEmpty(value()))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
else
{
data.GetType().GetProperty(propertyName).SetValue(data, value());
}
}
catch
{
//property doesn't exist
if (required)
data.DataValidationErrors.Add($"{valuePath} doesn't exist");
data.GetType().GetProperty(propertyName).SetValue(data, null);
}
}
else
{
throw new NullReferenceException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
}
}
Again. Works perfect for me, but not for him. I'm completely lost. Maybe I don't understand how the lamba/function parameters work 100%, but I thought it only got evaluated when value() is invoked.
I should also mention that when I debug this code, I can step into the Nuget package and when he hits the same line, he can't. This maybe a useful hint.

If jsonData (or jsonData.x) is null (as it seems to be at this point) it will crash and give you that error every time you call the method value().
You need to check why jsonData.x is null. Maybe it´s a race condition caused by another thread setting this value to null, maybe it´s because a bad jsonData initialization... Can´t say since that code is not here.

There are so many things wrong with your code, i can't resist.
First of all, instead of copy/pasting the same stuff over and over, you might want to use a variable:
var property = data.GetType().GetProperty(propertyName);
Second, you pass a Func<string> and execute it multiple times, why is it even a function then? Yet again, better only evaluate it once and use a variable...
var unwrapped = value();
That would solve the issue, that Roberto Vázquez' answer adresses.
Then you are misusing NullReferenceException, instead rather use a ArgumentException
Next issue, that valuePath is only used in the exception message, that is a poor design to my beliefs.
The generic T parameter isnt even used, so get rid of it.
Last but not least, that catch-block doing the exact thing that could possibily throw the exception again, i cant see any reason why you would do this.
Finnaly this whole thing becomes a little more clear but its still a mess.
public static void SetStringValue(IValidate data, string propertyName,
string valuePath, Func<string> value, bool required)
{
if(data == null)
throw new ArgumentNullException(nameof(data));
var property = data.GetType().GetProperty(propertyName);
if(property == null)
throw new ArgumentException($"In {data.GetType()} => SetStringValue. " +
$"Passed property {propertyName}, but property doesn't exist.");
var unwrapped = value();
try
{
if (string.IsNullOrEmpty(unwrapped))
{
if (required)
data.DataValidationErrors.Add($"{valuePath} can't be empty");
unwrapped = null; // this might be unecessary.
}
property.SetValue(data, unwrapped);
}
catch(Exception e)
{
// This is probably a bad idea.
property.SetValue(data, null);
if (required)
data.DataValidationErrors.Add(Atleast put a better message here. e.Message ...);
}
}

Related

Activator.CreateInstance works in one method but throws AmbiguousMatchException in another

I have two generic methods in the same class, and each uses exactly the same code to create instances. One works, the other throws an AmbiguousMatchException. Here is the code:
private static Dictionary<Type, AccessBase> _dictionary;
public static T Access<T>(Type type) where T : AccessBase
{
T instantiated;
if (_dictionary.ContainsKey(type))
{
instantiated = _dictionary[type] as T;
}
else
{
instantiated = (T)Activator.CreateInstance(type, _manager); //<- Works!
_dictionary.Add(type, instantiated);
}
return instantiated;
}
public static void RegisterAccess<T>(Type type) where T : AccessBase
{
if (type == null)
{
throw new ArgumentNullException(nameof(type));
}
if (_dictionary.ContainsKey(type))
{
return;
}
var instantiated = (T)Activator.CreateInstance(type, _manager); //<- Fails!
if (instantiated == null)
{
throw new ArgumentException($"{nameof(type)} cannot be registered");
}
_dictionary.Add(type, instantiated);
}
I would welcome any suggestions as to why and what to do about it... I have been tearing what is left of my hair out over this one!
Thanks to all of you for your input. I finally found the problem, which as it turns out is quite simple actually. At the point of failure the value of the _manager field is null... As soon as it is no longer null, it works.
To trap this I tried calling the first method at the same time as the second, and both failed. Tracking it through, I determined that the cause was the null value, since if you do it later in the process it works fine.
The original purpose of the code was to pre-register the access classes so that when they are needed they are ready to go and avoid the constant 'new' calls to generate these classes as they are needed. Given that it is now clear that this cannot happen at that point, the question is whether this is required at all. If we do it at a later point, there is not much reason to do it as it will get repeated every time a database is opened with each one not being added as it already exists.
I think we will end up abandoning the process that uses the second method, the pre-registration, in favour of the first method which is already used anyway and which automatically adds the instantiated classes only when they are needed and which already works fine at the later point.

Throwing exceptions at multiple points (refactoring)

I'm writing a function that takes user input, runs a procedure in our database, and compares the values. Along the way, I need to check that we've received proper input and then that the query has returned an acceptable value.
private void DoTheThing(int? userInput1, int? userInput2, int valuePassedIn)
{
if (userInput1 == null || userInput2 == null)
{
Exception ex = new Exception();
ex.Data.Add("Message", "You screwed up.");
throw ex;
}
var queryResult = 0; //execute a query using the non-null inputs
if (queryResult == null) //or otherwise doesn't return an acceptable value
{
Exception ex = new Exception();
ex.Data.Add("Message", "some other thing happened");
throw ex;
}
else
{
//We're good, so do the thing
}
}
A quick note about this: I'm aware of the argument against exceptions as flow control and that I'd be better off checking the user's input before I even get this far. I won't get into all the details, but please accept that I'm kind of stuck writing the function this way.
That having been said, here's my question:
Given that the only differences between the 2 exceptions here is the message and the time at which they are thrown, how can I clean this code up to be both DRY and avoid running unnecessary code after determining that there will be a problem?
I thought about using a goto and placing the error code there, but that really only moves the problem around. If I move the exception code to the bottom and check for a message variable (or something similar), then I'm just running code that doesn't need to be run in the first place.
I suggest not throwing Exception (which means something went wrong, no comments are available), but ArgumentNullException and InvalidOperationException classes. Another amendment is avoding arrow-head
antipattern:
private void DoTheThing(int? userInput1, int? userInput2, int valuePassedIn)
{
// What actually went wrong? An argument "userInput1" is null
if (null == userInput1)
throw new ArgumentNullException("userInput1");
else if (null == userInput2)
throw new ArgumentNullException("userInput2"); // ...or userInput2 is null
var queryResult = executeSomeQuery(userInput1, userInput2, valuePassedIn);
// What went wrong? We don't expect that null can be returned;
// so the operation "executeSomeQuery" failed:
// we've provided validated (not null) values and got unexpected return.
// Let it have been known.
if (null == queryResult)
throw new InvalidOperationException(
String.Format("Query ({0}, {1}, {2}) returned null when bla-bla-bla expected",
userInput1, userInput2, valuePassedIn));
// We're good, so do the thing
// Note that's there's no "arrow-head antipattern":
// we're not within any "if" or "else" scope
}
Edit: Since every *Exception is inherited from Exception you can put some info into Data:
Exception ex = new ArgumentNullException("userInput1");
ex.Data.Add("Some key", "Some value");
throw ex;
but often Message is a far better place to explain what had heppened.
You might be better off creating a BadInputException class and a NullQueryResultException class. These do two different things and throwing a specific exception is better than throwing a generic Exception(...). In fact I think FXCop or Visual Studio's Code Analysis will give you a warning about throwing generic Exceptions.
It's not really all that much new code to write.
public class BadInputException : Exception
{
public BadInputException()
{
this.Data.Add("Message", "You screwed up.")
}
}
Then instead of this:
Exception ex = new Exception();
ex.Data.Add("Message", "You screwed up.");
throw ex;
Do this:
throw new BadInputException();
Edit: moved the "You screwed up" message from the Message property to the Data collection to match what the OP wants.
I would create a method:
private void CheckResult(bool cond, string msg, string info) {
if (!cond)
return;
Exception ex = new Exception();
ex.Data.Add(msg, info);
throw ex;
}
and call
CheckResult(userInput1 == null || userInput2 == null, "Message", "You screwed up.");
and
CheckResult(queryResult == null, "Message", "You screwed up.");
I think the QuestionRefactoring Guard Clauses is helpful for you .
There are something about this in Replace Nested Conditional with Guard Clauses.
Hope it's useful.

Using Reflection to get the field/property that is being null compared?

How do I know the log the last property that is null?
For example,
var a = "somevalue";
......
......
if(a == null)
{
Log.Error(MethodBase.GetCurrentMethod().Name + "Property : a is null");
//blah blah
}
Like how I use the reflection to get the current method name, there should be some means by which I can log the latest local variables (or a property or fields)
that is being compared ? I use, log4net by the way to log the errors.
1) Is there any method to achieve this or should we manually log it?
2) Is there any custom method that prints the class -> MethodName -> Propertyname(or FieldName) that is null?
Thanks for your time in advance.
As mentioned by #fsimonazzi, "a" would be a local variable.
That being said there is still no way to examine the current compare operation as in MSIL there is no formal concept of an IF block - only conditional jumps.
If you wanted to get really crazy with the reflection, you may be able to find the current executing instruction and look around near that for a variable, but even then, you will not find the name - only a reference - as names are only used prior to compilation.
Either way, reflection is not going to help you here.
Instead, try using Exceptions - specifically ArgumentNullException. This body of code would become:
void doStuff(string param1, int param2)
{
if (param == null)
throw new ArgumentNullException("param1", "param1 must not be null");
if (param2 < 0)
throw new ArgumentOutOfRangeException("param2", "param2 should be non-negative.");
//method body
}
then, when you call the method, you can catch the exception and log it - no matter what it may be.
public static void Main(string[] args)
{
try
{
doStuff(null, 3);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
Tools like FxCop can help make sure that you are properly validating each parameter.
Properties are actually implemented as methods, so reflection could help you there. If, for example, you were validating in a property and wanted to log the position automatically, you could.
private object _cachedObject = null;
public object CachedObject
{
get
{
if (_cachedObject == null)
{
log(MethodBase.GetCurrentMethod().Name, "creating cached object");
_cachedObject = createCachedObject();
}
return _cachedObject;
}
}
The .Net Framework 4.5 also brings with it a new attribute that can be used to replace the MethodBase.GetCurrentMethod().Name construct you are using to get the method name. See [CallerMemberNameAttribute][3].

Null check returns true for non-null value

Having an odd problem. It's happened a few times over the years, but I've never been able to figure out why. Always solved it by rearranging the code I had in place, but would like to know is there's a more proper way of dealing with it, or at least figuring out what's behind it.
Non-working version:
public bool CaptureFrame(ArrayCache cache)
{
if (cache == null)
throw new ArgumentNullException("cache");
DataArray frame = cache.CacheData;
if (frame == null)
throw new ArgumentNullException("cache.CacheData");
// do stuff
}
Working version:
public bool CaptureFrame(ArrayCache cache)
{
if (cache == null)
throw new ArgumentNullException("cache");
if (cache.CacheData == null)
throw new ArgumentNullException("cache.CacheData");
DataArray frame = cache.CacheData;
// do stuff
}
The problem is this: frame is not null (at least according to the debugger, and by any measure I can trace of the code), however when it does the if (frame == null) check, it comes out true and throws the exception. I rewrote to check cache.CacheData and it works fine, but it really shouldn't make any difference to the code logic.
I managed to find one other question on the site with a similar problem, which ended up being related to the == and != operators being overloaded. Those operators are not overloaded for the class in question in my code, and it's a standalone class so there's nothing for it to inherit.
Edit: John Saunders requested code for the CacheData property:
private DataArray cacheData;
public DataArray CacheData
{
get
{
return cacheData;
}
set
{
cacheData = value;
}
}
looks like you are mapping the exception in the non working one then calling
DataArray frame = cache.CacheData;
but what if cache.CacheData if null then you are assigning it to DataFrame.. it's always best in my opinion to do the Check for null first before assigning or assuming your second one looks fine.. prehaps instead of throwing an exception maybe you could trap the exception and try some test cases for both scenarios

Cache == null? Is it possible?

Is it legal to make the following statement:
if(Cache[CACHE_KEY] == null)
{
//do something to form cache
}
else
{
//do something else that uses cache
}
I'm not sure my program is actually functioning properly (even though it compiles) and am wondering if a cache doesn't exist is it set to null?
Yes, that is legal (but the question in the title is not, see below for details).
Though, it may be wise to check that the type in the cache is what you're expecting rather than having to do this check twice, such as:
//in English, the following line of code might read:
// if the item known in the cache by the specified key is in
// in fact of type MyExpectedReferenceType, then give me it
// as such otherwise, give me a null reference instead...
var myCachedInstance = Cache[key] as MyExpectedReferenceType;
if (myCachedInstance == null)
{
//we retrieved a reference to an instance of an MyExpectedReferenceType
}
else
{
//oh, no - we didn't!
}
On re-reading your question though, and thinking about your program not working properly, I'm tempted to say you have bigger issues than this; how is your program not working correctly? The Cache instance itself will never be null while accessible - it is a read-only field of Page. However, your expected cached value could be null and, if this is the problem, you should be receiving a NullReferenceException - is that the case?
UPDATE:
To address your comment, check out the comments I added to the code.
Very much legal; rather its better to check for a value before performing action, especially to make sure that key has not slided-out, or expired, etc.
There is a potential race condition in the code you posted:
if(Cache[CACHE_KEY] == null)
{
//do something to form cache
}
else
{
// Another thread could have removed CACHE_KEY from the Cache before you get here
}
It's better to first extract the object from the cache, then test it for null, e.g.:
MyObject cachedObject = Cache[CACHE_KEY] as MyObject;
// or MyObject cachedObject = (MyObject) Cache[CACHE_KEY]; if you know it is of type MyObject
if(cachedObject == null)
{
cachedObject = ... // generate the cached object
Cache.Insert(CACHE_KEY, cachedObject, ...);
}
// use cachedObject
Yes it`s possible, Cache will always be initialize (like session and application obj)
But you can check if a key in the cache is null

Categories

Resources