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

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].

Related

What is the appropriate Exception to throw upon a runtime type mismatch in C#

Essentially I am creating a little IL injection DLL that uses MONO.CECIL and C#, primarily as a learning exercise for myself but also for my own future hobbyist use.
I am not particularly skilled with exceptions (or C#) and am unsure what the appropriate exception to throw is for when a runtime type mismatch occurs.
For example : I have a method that INJECTS a method call at a given point in a target DLL. The method takes as an arguement a Collection (parameters) to represent the variables to pass as parameters to the newly injected method call.
Before injecting I check for type parity between each member of the Collection (parameters) and the Collection from the method whose call I am injecting.
On a mismatch I want to throw an exception. But I could not really find any that fit. I would prefer to use existing exceptions where possible, rather than creating my own.
Here is the code :
private static bool ParameterParity(Collection<ParameterDefinition> p, Collection<VariableDefinition> v)
{
if (p.Count != v.Count)
{
return (false);
}
else
{
int index = 0;
foreach (ParameterDefinition parameter in p)
{
if (parameter.ParameterType.MetadataType != v[index].VariableType.MetadataType)
{
return (false);
}
index++;
}
}
return (true);
}
Here is the call where the exception will be thrown :
if (ParameterParity(source.Parameters, parameters) == false)
{
throw new NotImplementedException($"{Helper.AddParenthesis(nameof(PreInject), Helper.ParenthesisE.Square)}" +
$" : Parameter mismatch in TYPE or NUMBER" +
$". Functionality not supported.");
}
I temporarily have used the NOT IMPLEMENTED exception, but would prefer something more appropriate. A suggestion as to the appropriate Exception would be appreciated.
Thanks in advance.

C# lambda null runtime binding

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

StackFrame behaving differently in release mode

Here is my code:
public class UserPreferences
{
/// <summary>
/// The EMail signature.
/// </summary>
[UserPreferenceProperty(Category = "Email", DefaultValue = "My default value")]
public static string Signature
{
get
{
return UserPreferenceManager.GetValue();
}
set
{
UserPreferenceManager.SetValue(value);
}
}
}
public static string GetValue()
{
if (((VTXPrincipal)Thread.CurrentPrincipal).VTXIdentity.OperatorID == null)
{
throw new Exception("Missing Operator ID");
}
string value = string.Empty;
var frame = new StackFrame(1); ***** <------ problem here.....
var property = frame.GetMethod();
var propertyname = property.Name.Split('_')[1];
var type = property.DeclaringType; ***** <------ problem here.....
if (type != null)
{
var userPreference = typeof(UserPreferences).GetProperty(propertyname).GetCustomAttributes(true).FirstOrDefault() as UserPreferencePropertyAttribute;
if (userPreference != null)
{
string category = userPreference.Category;
string description = propertyname;
value = GetValue(category, description, ((VTXPrincipal)Thread.CurrentPrincipal).VTXIdentity.OperatorID);
if (value == null)
{
// always return something
return userPreference.DefaultValue;
}
}
else
{
throw new Exception("Missing User Preference");
}
}
return value;
}
Inside the GetValue method, StackFrame works differently in release mode vs. debug mode.
In debug mode, I correctly get the property name as signature
But in Release mode, property name is GetUserPreferenceValueTest because this is the test method that makes the calls as clients.
There fore my code works in debug mode but fails in release mode.
Q. How can I use StackFrame properly so it works in Debug vs. Release modes.
Q. Is there any other way to get calling property name and related information at run time?
I answered a similar question once, please read my answer here.
In short, this is a very bad design decision because your method is a hypocrite—it talks different to different callers but doesn't tell it in open. Your API should never, ever rely on who calls it. Also, the compiler can break the stack trace in an unexpected way due to language features like lambdas, yield and await, so even if this worked in Release mode, it would certainly break some day.
You're effectively building a complex indirection mechanism instead of using language feature designed for passing information to methods—method parameters.
Why do you use attributes? Do you read them elsewhere?
If you do, and you don't want to repeat "Email" both as parameter to GetValue call and attribute value, you may consider passing a property Expression<> to GetValue, which will extract the attribute. This is similar to your solution, but it is explicit:
[UserPreferenceProperty(Category = "Email", DefaultValue = "My default value")]
public string Signature
{
get { return GetValue (prefs => prefs.Signature); }
set { SetValue (prefs => prefs.Signature, value); }
}
This answer shows how to implement this.
I see you are checking Thread.CurrentPrincipal in your code. Again, this is not a really good practice because it is not obvious to client code that accessing a property can result in an exception. This is going to be a debugging nightmare for someone who supports your code (and trust me, your code may run for years in production, long after you move onto another project).
Instead, you should make VTXIdentity a parameter to your settings class constructor. This will ensure the calling code knows you enforce security on this level and by definition knows where to obtain this token. Also, this allows you to throw an exception as soon as you know something is wrong, rather than when accessing some property. This will help maintainers catch errors earlier—much like compile errors are better than runtime errors.
Finally, while this is a fun exercise, there are plenty performant and tested solutions for storing and reading configuration in C#. Why do you think you need to reinvent the wheel?
Assuming your problem survives the discussion of whether you could just use another library rather than rolling your own... if you find yourself using C# 5 &.NET 4.5, take a look at the CallerMemberName attribute. With CallerMemberName you can modify your GetValue() method signature to be
public static string GetValue([CallerMemberName] string callerName = "")
The property can then call GetValue() with no parameter and you'll get the property name passed into GetValue() as you want.

How to refactor code with try-catch-finally

I have to create a bunch of methods that look like this. The things that change will be the method name, the return type and the lines marked in the middle - the rest will be the same. Is there a clean way to refactor this so that I don't repeat myself?
private bool CanPerform(WindowsIdentity identity, string applicationName, int operation)
{
IAzApplication3 application = null;
IAzClientContext3 context = null;
try
{
application = this.store.OpenApplication(applicationName, null) as IAzApplication3;
ulong token = (ulong)identity.Token.ToInt64();
context = application.InitializeClientContextFromToken(token, null) as IAzClientContext3;
// lines that change go here
}
catch (COMException e)
{
throw new SecurityException(string.Format("Unable to check operation '{0}'", operation), e);
}
finally
{
Marshal.FinalReleaseComObject(context);
Marshal.FinalReleaseComObject(application);
}
}
I realise this is probably basic stuff but I work alone so there's no one else to ask.
It sounds like a delegate would be appropriate here, with a generic method to cover the return type changing:
private T ExecuteWithIdentity<T>(WindowsIdentity identity,
string applicationName, int operation,
Func<IAzApplication3, IAzClientContext3, T> action)
{
IAzApplication3 application = null;
IAzClientContext3 context = null;
try
{
application = this.store.OpenApplication(applicationName, null) as IAzApplication3;
ulong token = (ulong)identity.Token.ToInt64();
context = application.InitializeClientContextFromToken(token, null) as IAzClientContext3;
return action(application, context);
}
catch (COMException e)
{
throw new SecurityException(
string.Format("Unable to check operation '{0}'", operation), e);
}
finally
{
Marshal.FinalReleaseComObject(context);
Marshal.FinalReleaseComObject(application);
}
}
Then you put the code for each check in a separate method, or even just use a lambda expression:
bool check = ExecuteWithIdentity(identity, "Foo", 10,
(application, context) => context != null);
or
string check = ExecuteWithIdentity(identity, "Foo", 10, SomeComplexAction);
...
private static string SomeComplexAction(IAzApplication3 application,
IAzClientContext3 context)
{
// Do complex checks here, returning whether the user is allowed to
// perform the operation
}
You may want to change the delegate type of course - it's not clear what operation is meant to be used for, for example.
I would also strongly consider casting instead of using as. If the application or context is returned from OpenApplication/InitializeClientContextFromTokenas a non-null value which just isn't the right type, do you really want to handle that the same was as a null value being returned?
You could do your error handling slightly higher up the stack, so rather than catching and rethrowing the exception inside the method you could do it where the method is called?
If your method calls are all wrapped in a Manager class that might save a bit of time. If they're just ad-hoc called everywhere then naturally maybe not :)
I hope that might help.

Unhandled Exception in List Sort

So, I have a list containing a custom class, MyClass
MyClass has properties, which can be null (but aren't meant to be).
When this class is sorted, using a custom sorter, where the sorter accesses this null property and throws an exception, the exception is considered unhandled, even though there is a try-catch block around the sort method.
Now for some reason the exception still gets written to the console, which is what the exception handler is doing.
I have a real application with this same issue, causing my unit tests to fail, even though the exception is handled correctly and I cannot explain this.
So I have attached some sample code to explain myself better, run this from VS.
Updated Code
Results:
System.InvalidOperationException
Failed to compare two elements in the array.
Done!
So it seems to be handling my custom exception, and throwing its own?
using System;
using System.Collections.Generic;
using System.Data;
namespace TestSortException
{
class Program
{
static void Main()
{
try
{
var list = new List<MyClass>
{
new MyClass("1"),
new MyClass(null),
new MyClass("fdsfsdf")
};
list.Sort(new MyClassSorter());
}
catch(Exception e)
{
Console.WriteLine(e.GetType());
Console.WriteLine(e.Message);
}
Console.WriteLine("Done!");
Console.ReadLine();
}
}
class MyClassSorter : IComparer<MyClass>
{
public int Compare(MyClass x, MyClass y)
{
// try
// {
if (x.MyString == y.MyString)
return 0;
// Unhandled??? Exception here
if (x.MyString.Length > y.MyString.Length)
return 1;
return -1;
// }
// catch (Exception)
// {
// return -1;
// }
}
}
class MyClass
{
private string _myString;
public string MyString
{
get
{
if (_myString == null) throw new DataException("MyString is Null");
return _myString;
}
}
public MyClass(string myString)
{
_myString = myString;
}
}
}
There's a try/catch block round the Sort method, yes - and that catch block catches the exception. In other words, Sort throws an exception and your catch block catches it. It doesn't propagate out beyond Main - so "Done!" is printed.
This is exactly what I'd expect. In what way is it "unhandled" in your experience? Were you expecting Sort not to throw the exception? It needs to do something to indicate the failure to compare two elements, and this seems to be the most appropriate course of action.
In what way are your unit tests failing? Are you deliberately giving them invalid data? How do you want your comparison code to react to invalid data? If it should ignore it (and return a comparison based on another property), then you should actively check the property rather than letting an exception propagate. In most cases I'd rather allow the exception if this indicates that there's a bug earlier on though.
EDIT: Based on your other comments, it sounds like you're doing the appropriate thing, letting the exception bubble up - but it's not clear in what way you're seeing the exception not be handled.
If you're running in the debugger, it may be breaking on the exception being thrown, but that doesn't mean it won't be handled. Try either changing your exception settings or running without the debugger.
EDIT: Yes, Sort will catch the exception and throw an InvalidOperationException instead - but you can use the InnerException property of that exception to get hold of the original one. It's unfortunate that the documentation doesn't specify this :(
For example, when it checks that string "1" isn't equal to null. But it wants then to compare lengths of "1" string and null => which is impossible.
I assume you work with .Net Framework 4.0. The new thing there is that a NullRefenrenceException can not be caught any more (similar to OutOfMemory exception).

Categories

Resources