This question already has answers here:
How to create a reference to a value-field
(4 answers)
Closed 2 years ago.
I'm working on an OpenGL game engine as a passion project and im using the UI library "Dear ImGUI" to display and debug values similar to Unity's inspector. I'm having trouble thinking of a way to get a reference to the field I'm trying to debug.
Here is the code i have got at the moment but the problem is that its not a reference to the actual field, its just a reference to a local variable (value) and as such, it doesnt actually set the variable that I debug in the GUI. From what i've been able to see, there is no clean cut way to get the reference.
protected override void OnImGUIRender(FrameEventArgs e)
{
ImGui.PushFont(font);
ImGui.ShowDemoWindow();
//Scene Window
{
ImGui.Begin("Scene");
ImGui.BeginTabBar("1");
ImGui.BeginTabItem("Heirachy");
if (ImGui.TreeNode("Scene"))
{
foreach (var obj in (LayerStack.Layers.FirstOrDefault(x => x.GetType() == typeof(GameLayer)) as GameLayer).scene.GameObjects)
{
if (ImGui.Selectable(obj.Name))
selectedGameObject = obj;
}
ImGui.TreePop();
}
ImGui.EndTabItem();
ImGui.EndTabBar();
ImGui.Dummy(new System.Numerics.Vector2(0, 40));
ImGui.BeginTabBar("Properties");
ImGui.BeginTabItem("Properties");
if (selectedGameObject != null)
{
ImGui.Text(selectedGameObject.Name);
foreach (var c in selectedGameObject.components)
{
if (ImGui.TreeNode(c.GetType().Name))
{
var fields = c.GetType().GetFields();
foreach (var field in fields)
{
ImGui.DragFloat3(field.Name, field.refValue); <-- Focused line
}
ImGui.TreePop();
}
}
}
else
ImGui.Text("No Currently Selected Gameobject");
ImGui.EndTabItem();
ImGui.EndTabBar();
ImGui.End();
ImGui.Begin("Debug");
ImGui.Text("Gameobjects: " + LayerStack.GameObjectCount);
ImGui.End();
}
base.OnImGUIRender(e);
}
Is there any way I can get a reference to the actual field that is being looped over in the foreach? In my head I would imagine it looking something like this:
ImGui.DragFloat3(field.Name, field.Reference);
Thanks!
Edit:
I found my personal solution to be in the code below but massive thanks to #pinkfloydx33 for helping me to understand the problem better and provide a high quality answer.
var fields = c.GetType().GetFields();
foreach (var field in fields)
{
var value = (field.FieldType)field.GetValue(c);
ImGui.DragFloat3(field.Name, field.refValue);
field.SetValue(c, value);
}
Part of the problem you are experiencing is due to the fact those field values are structs. You only end up operating on copies of them. But we can get around this by building a delegate that accepts as its only parameter an object of the containing type (the type who's fields you are inspecting). This delegate will in turn call the method you are trying to invoke, passing the object's field under the hood with ref.
This solution below assumes that the methods you want to invoke (ImGui.Drag3, ImGui.Checkbox) always have two parameters -- string name and ref T value. In other words, a hypothetical method that operated on int fields would have to be declared as ImGui.DoSomethingToInt(string name, ref int value)
using System.Linq.Expressions;
using System.Reflection;
using System.Collection.Generic;
public static class ComponentHelpers
{
// helper function to get the MethodInfo for the method we want to call
private static MethodInfo GetStaticMethod(Expression<Action> expression)
{
if (expression.Body is MethodCallExpression body && body.Method.IsStatic)
return body.Method;
throw new InvalidOperationException("Expression must represent a static method");
}
// helper field we can use in calls to GetStaticMethod
private static class Ref<T>
{
public static T Value;
}
// Define which method we want to call based on the field's type
// each of these methods must take 2 parameters (string + ref T)
private static readonly Dictionary<Type, MethodInfo> Methods = new Dictionary<Type, MethodInfo>
{
[typeof(Vector3)] = GetStaticMethod(() => ImGui.Drag3(default, ref Ref<Vector3>.Value)),
[typeof(bool)] = GetStaticMethod(() => ImGui.Checkbox(default, ref Ref<bool>.Value))
};
// store the compiled delegates so that we only build/compile them once
private static readonly Dictionary<FieldInfo, Action<Component>> Delegates = new Dictionary<FieldInfo, Action<Component>>();
// this method will either build us a delegate, return one we've already built
// or will return null if we have not defined a method for the specific type
public static Action<Component> GetActionFor(FieldInfo field)
{
if (!Methods.TryGetValue(field.FieldType, out var method))
return null;
if (Delegates.TryGetValue(field, out var del))
return del;
// type the parameter as the base class Component
var param = Expression.Parameter(typeof(Component), "x");
var lambda = Expression.Lambda<Action<Component>>(
Expression.Call(
method,
// Pass the field's name as the first parameter
Expression.Constant(field.Name, typeof(string)),
// pass the field as the second parameter
Expression.Field(
// cast to the actual type so we can access fields of inherited types
Expression.Convert(param, field.ReflectedType),
field
)
),
param
);
return Delegates[field] = lambda.Compile();
}
}
Once we've done that, we can update your main loop to look like the following:
var fields = c.GetType().GetFields();
foreach (var field in fields)
{
var action = ComponentHelpers.GetActionFor(field);
if (action == null) // no method defined
continue;
// invoke the function passing in the object itself
action(c);
}
How do I convert a CSV string to an array of a type that is only known at run time. Say I have 2 array fields in my class of different types declared as int[] intArray and string[] strArray. I want a single function where I pass in 2 parameters the field name and CSV string. I can use the ...; FieldInfo f =... ; Type t = f.FieldType.GetElementType(); But what I can't do is declare List<t> because t is a variable and not a type. I saw one post suggesting csv.Split(',').Select(s => Convert.ChangeType(s, t)).ToArray() but this comes out as an object array not an int or string array; another post saying ...; var list = (IList) Activate.CreatInstance(...), which is fine that I can call list.Add(...) but then what do I do as I need an Array of t.
I'd recommend using a nuget package to do this parsing. CsvHelper has an example of how to deserialize to a given type.
I have bitten the bullet on this one and so will have to update my code if I need a new type like array of float numbers say is required but this suffices for what I need today, and I do agree with the other mentions about CSV what if my values had commas say addresses and came in as "\"12 George St, Sydney\",\"200 Sussex St, Sydney\"" then I would have to consider advanced CSV however again this is all I need for today.
class SetPropertyByName
{
public object this[string fieldName]
{
set
{
FieldInfo field = this.GetType().GetField(fieldName, BindingFlags.Public | BindingFlags.Instance);
if (null != field)
{
if (field.FieldType.IsArray && value is String)
{
string newValue = (string)value;
if (string.IsNullOrEmpty(newValue))
value = null;
else
{
var conversionType = field.FieldType.GetElementType();
if (conversionType == typeof(string))
{
value = newValue.Split(',').ToArray();
}
else if (conversionType == typeof(int))
{
value = newValue.Split(',').Select(s => Convert.ToInt32(s)).ToArray();
}
}
field.SetValue(this, value);
}
else
field.SetValue(this, Convert.ChangeType(value, field.FieldType));
}
}
}
}
Given any object, I want to be able to retrieve the value of a property and any "depth".
var name = myObject.GetValue<String>("Name")
or
var father_name = myObject.GetValue<String>("Father.Name")
This is easy and I'm able do achieve it with the following code:
public static T GetValue<T>(this Object obj, String fqname)
{
try
{
Object value = obj;
foreach (var prop in fqname.Split('.').Select(s => value.GetType().GetProperty(s)))
{
value = prop.GetValue(value, null);
}
if (value is T)
{
return (T)value;
}
else
{
// if the type requested is not the same as the stored, attempt a blind conversion
var converter = TypeDescriptor.GetConverter(typeof(T));
return (T)converter.ConvertFromInvariantString(value.ToString());
}
}
catch (NotSupportedException)
{
throw new InvalidCastException($"Cannot convert value to reuested type");
}
}
Now the problem is that this doesn't work for arrays, like:
var main_street = myObject.GetValue<String>("Addresses[0].StreetName")
Not even for the cases of arrays of arrays and so on...
I can start adding these conditions and special cases to my code but before that I figured, as C# already does this, maybe we could leverage some code parsing strategy, Roslyn, ... don't know, something that doesn't feel like reinventing the wheel and supports as many cases as possible.
Any ideas?
I have the need to do a few checks like this:
if(thisInstance is ThatClass || thisInstance is ThatOtherClass)
I actually won't be needing to do a lot of these, so I could simply write it as it is above, but I'd still prefer doing this in a more tidy way, eg. like this:
Type[] arrayOfClasses = new Type[] { typeof(ThatClass), typeof(ThatOtherClass))}
if(isOfAnyType(thisInstance, arrayOfClasses))
But for some reason I can't get it to work. For some reason even though the string representations of
thisInstance.GetType()
and
typeof(ThatClass)
would be the same,
thisInstance.GetType().IsInstanceOfType(type)
will still always result in false.
In case it makes a difference, this is a Unity project, so if calling one further GetType() for the comparable items (eg. thisInstance.GetType().GetType()) the result is always System.MonoType, in which case the IsInstanceOfType always returns true, which of course isn't useful either.
Any ideas why the comparison fails or how to make it work? Or should I just give up and simply use the "thisInstance is ThatClass" wherever needed?
You could use something like this. The method checks a generic object whether it is of any of the types within the array and returns a bool.
public static bool IsOfAnyType<T>(T obj, Type[] types)
{
bool isOfAnyType = false;
for (int i = 0; i < classes.Length; i++)
{
if (types[i].IsAssignableFrom (obj.GetType()))
{
isOfAnyType = true;
break;
}
}
return isOfAnyType;
}
You can use isSubclass:
thisInstance.GetType().IsSubclassOf(typeof(ThatClass))
To get your desired way to work you could use this method:
public static bool IsOfAnyType(object obj, Type[] types)
{
return types.Any(type => type.IsInstanceOfType(obj));
}
If you can't use Linq you can write the method like this:
public static bool IsOfAnyType(object obj, Type[] types)
{
foreach (var type in types)
{
if (type.IsInstanceOfType(obj))
return true;
}
return false;
}
To test this I used this code:
Type[] typesToCheck = { typeof(ThatClass), typeof(ThatOtherClass) };
ThatClass input1 = new ThatClass();
ThatOtherClass input2 = new ThatOtherClass();
if (IsOfAnyType(input1, typesToCheck))
Console.WriteLine("Hello world from " + input1.GetType());
if (IsOfAnyType(input2, typesToCheck))
Console.WriteLine("Hello world from " + input2.GetType());
I've noticed this code crops up a lot in my constructors:
if (someParam == null) throw new ArgumentNullException("someParam");
if (someOtherParam == null) throw new ArgumentNullException("someOtherParam");
...
I have a few constructors where several things are injected and must all be non-null. Can anyone think of a way to streamline this? The only thing I can think of is the following:
public static class ExceptionHelpers
{
public static void CheckAndThrowArgNullEx(IEnumerable<KeyValuePair<string, object>> parameters)
{
foreach(var parameter in parameters)
if(parameter.Value == null) throw new ArgumentNullException(parameter.Key);
}
}
However, the usage of that would be something like:
ExceptionHelper.CheckAndThrowArgNullEx(new [] {
new KeyValuePair<string, object>("someParam", someParam),
new KeyValuePair<string, object>("someOtherParam", someOtherParam),
... });
... which doesn't really help streamline the code. Tuple.Create() instead of KVPs doesn't work because Tuple's GTPs aren't covariant (even though IEnumerable's GTP is). Any ideas?
Update for C# 7
You can use a throw expression with the null coalescing operator. Here is an example from that page:
public string Name
{
get => name;
set => name = value ??
throw new ArgumentNullException(paramName: nameof(value), message: "New name must not be null");
}
Original Answer
Personally, I use the ThrowIfNull extension method. I don't know who to credit but I definitely didn't invent it. It's nice because you can do assignment with the return value:
public static T ThrowIfNull<T>(this T argument, string argumentName)
{
if (argument == null)
{
throw new ArgumentNullException(argumentName);
}
return argument;
}
Usage:
this.something = theArgument.ThrowIfNull("theArgument");
// or in C# 6
this.something = theArgument.ThrowIfNull(nameof(theArgument));
(Although some people think it's weird to call an extension method on a null instance)
If you really want to check more than one argument at a time, your example might be more streamlined if you used a params signature like so:
public static void CheckAndThrowArgNullEx(params object[] argsAndNames)
{
for (int i = 0; i < argsAndNames.Length; i += 2)
{
if (argsAndNames[i] == null)
{
string argName = (string)argsAndNames[i + 1];
throw new ArgumentNullException(argName);
}
}
}
and the usage would be:
CheckAndThrowArgNullEx(arg1, "arg1", arg2, "arg2");
// or in C# 6
CheckAndThrowArgNullEx(arg1, nameof(arg1), arg2, nameof(arg2));
On second thought, as KeithS mentions in the comments, it would probably be better to implement this as a set of overloads rather than using params object[] like this:
static void Check(object arg1, string arg1Name) { ... }
static void Check(object arg1, string arg1Name, object arg2, string arg2Name) { ... }
// and so on...
Try this: One line.
accounts = accounts ?? throw new ArgumentNullException(nameof(accounts));
Also, use nameof(), if the variable is ever renamed you will not have to hunt down all the "variable"s, let nameof() do that.
.NET 6 and beyond
There is a new method in .NET API ArgumentNullException.ThrowIfNull(someParameter).
This method is probably the best option which you can get.
C# 11 (currently as proposal)
Use new Bang Bang operator !! on a parameter to implicit check for null.
public string SomeFunction(Foo foo!!)
{
// here, foo is already checked for null
// ArgumentNullException(nameof(foo)) is thrown when foo = null
return $"Here is {foo.Bar}";
}
TL;DR
The compiler will emit this code for every !! use
if (someArgument is null)
{
throw new ArgumentNullException(nameof(someArgument));
}
Our SomeFunction will be transformed into
public string SomeFunction(Foo foo!!)
{
if (foo is null)
{
throw new ArgumentNullException(nameof(foo));
}
return $"Here is {foo.Bar}";
}
There are several way to go about this.
Option A:
Break your functions into two - validation and implementation (you can see examples of this in Jon Skeet's EduLinq).
Option B:
Use code contracts that expect the parameters to be non-null.
Option C:
Using aspect oriented technologies such as code weaving to extract these checks out into an aspect. (as J Torres answered).
Option D:
Use Spec#, as CodeInChaos commented.
Option E:
???
Upticks for most of you guys; your answers contributed to the solution I finally arrived at, which incorporated bits and pieces but ultimately is different from all of them.
I created a couple of static methods that work on lambda expressions of a specific form (EDIT - small change; the methods can't be generic or they will require all expressions to return the same type. Func is fine instead, with an extra condition in the GetName method to unwrap the cast):
public static class ExpressionReader
{
/// <summary>
/// Gets the name of the variable or member specified in the lambda.
/// </summary>
/// <param name="expr">The lambda expression to analyze.
/// The lambda MUST be of the form ()=>variableName.</param>
/// <returns></returns>
public static string GetName(this Expression<Func<object>> expr)
{
if (expr.Body.NodeType == ExpressionType.MemberAccess)
return ((MemberExpression) expr.Body).Member.Name;
//most value type lambdas will need this because creating the
//Expression from the lambda adds a conversion step.
if (expr.Body.NodeType == ExpressionType.Convert
&& ((UnaryExpression)expr.Body).Operand.NodeType
== ExpressionType.MemberAccess)
return ((MemberExpression)((UnaryExpression)expr.Body).Operand)
.Member.Name;
throw new ArgumentException(
"Argument 'expr' must be of the form ()=>variableName.");
}
}
public static class ExHelper
{
/// <summary>
/// Throws an ArgumentNullException if the value of any passed expression is null.
/// </summary>
/// <param name="expr">The lambda expressions to analyze.
/// The lambdas MUST be of the form ()=>variableName.</param>
/// <returns></returns>
public static void CheckForNullArg(params Expression<Func<object>>[] exprs)
{
foreach (var expr in exprs)
if(expr.Compile()() == null)
throw new ArgumentNullException(expr.GetName());
}
}
... which can be used thusly:
//usage:
ExHelper.CheckForNullArg(()=>someParam, ()=>someOtherParam);
This reduces the boilerplate to one line, without third-party tools. The ExpressionReader, and thus the exception-generating method, work on any lambda of the form ()=>variableName that compiles in the caller, meaning it works for local variables, parameters, instance fields and instance properties, at least. I haven't checked to see if it works on statics.
In c# 10 you can just do this:
ArgumentNullException.ThrowIfNull(z);
And you will got this error:
System.ArgumentNullException: Value cannot be null. (Parameter 'z')
at System.ArgumentNullException.Throw(String paramName)
at System.ArgumentNullException.ThrowIfNull(Object argument, String paramName)
at ConsoleApp1.SomeClass.Join(String a, String b)
Under the hood, it use the new CallerArgumentExpression attribure.
public class TestClass
{
public TestClass()
{
this.ThrowIfNull(t=>t.Str, t=>t.Test);
//OR
//this.ThrowIfNull(t => t.X)
// .ThrowIfNull(t => t.Test);
}
string Str = "";
public TestClass Test {set;get;}
}
public static class SOExtension
{
public static T ThrowIfNull<T>(this T target, params Expression<Func<T, object>>[] exprs)
{
foreach (var e in exprs)
{
var exp = e.Body as MemberExpression;
if (exp == null)
{
throw new ArgumentException("Argument 'expr' must be of the form x=>x.variableName");
}
var name = exp.Member.Name;
if (e.Compile()(target) == null)
throw new ArgumentNullException(name,"Parameter [" + name + "] can not be null");
}
return target;
}
}
In c# 7 can be done like this:
_ = someParam ?? throw new ArgumentNullException(nameof(someParam));
After release optimisation you will get:
if (someParam == null)
throw new ArgumentNullException(nameof(someParam));
If you aren't opposed to third party utilities, PostSharp provides clean ways to inject such validations. This blog post provides a solution to your problem.
Update: See new Validating-parameters features in PostSharp 3
How about an extension method?
public static void ThrowExceptionIfNull(this object argument, string argumentName)
{
if(argument == null)
throw new ArgumentNullException(argumentName);
}
Then your code at least reads a little more fluently:
someParam.ThrowExceptionIfNull("someParam");
Otherwise, I would agree with the others to split the functionality or use AOP (ie. PostSharp)
Well, the boilerplate is hard to avoid. You could switch to using the Bertrand Meyers' Eiffel programming language and EiffelStudio instead of C# and Visual Studio and start practicing "design by contractâ„¢".
Eiffel is fully CLR-compliant these days.
There are a lot of valid solutions already, but here's my take:
using System.Diagnostics;
using System.Reflection;
public SomeConstructor(int? par1, int? par2, string par3)
{
CheckThrowNull(par1, par2, par3);
//rest of constructor code...
}
///<param name="values"> Values must be given in order </param>
public static void CheckThrowNull(params object[] values)
{
StackTrace stackTrace = new StackTrace();
ParameterInfo[] parameters = stackTrace.GetFrame(1).GetMethod().GetParameters(); //get calling method's parameters (or constructor)
if (parameters.Length != values.Length)
{
throw new ArgumentException("Incorrect number of values passed in");
}
for (int i = 0; i < parameters.Length; i++)
{
if (values[i] == null)
{
//value was null, throw exception with corresponding parameter name
throw new ArgumentNullException(parameters[i].Name);
}
}
}
The general idea is that two parallel arrays are established, one of type ParameterInfo, and one containing the values of the parameter. The latter has to passed in because parameter values aren't easily (and I think impossible) obtainable via reflection. To give credit where it is due, I found how to get the calling method here: http://www.csharp-examples.net/reflection-calling-method-name/
Personally, I don't like using System.Diagnosics except for debugging, so I would make a slight modification, having calling code be:
CheckThrowNull(MethodBase.GetCurrentMethod(), par1, par2, par3);
and the method being
CheckThrowNull(MethodBase method, params object[] values)
{
ParameterInfo[] parameters = method.GetParameters();
//rest of code same
}
The down-side is its a little non-extensible and can't easily be made to check if just some of the arguments are null.
I wrote benchmark application with multiple variations of extracting argument name (via anonymous class + reflection / MemberExpression / Func / etc)
Github link to benchmark sources: https://github.com/iXab3r/NullCheckCompetition
I got results, that are showing, that the fastest method is through use of anonymous class.
.NET 40 / X64
Fail (i.e. argument IS null and name extraction method is executed)
FailAnonymousClass 67.87 ns
FailDoubleLambda 643.98 ns
FailLazyAnonymousClass 69.36 ns
FailRawCheck 1.08 ns
FailSingleLambda 643.27 ns
Success (i.e. argument is not null)
SuccessAnonymousClass 6.33 ns
SuccessDoubleLambda 8.48 ns
SuccessLazyAnonymousClass 8.78 ns
SuccessRawCheck 1.08 ns
SuccessSingleLambda 628.28 ns
I think most of the above are ok but none of them are really an improvement to what you already have so I would just go for the KIS, Keep It Simple, and that is what you started with.
It's clean, extremly readable and its fast. The only thing it's a bit long
Update for C# 10 (.NET >= 6):
_person = person.ThrowIfNull();
public static T ThrowIfNull<T>(this T? argument, string? message = default, [CallerArgumentExpression("argument")] string? paramName = default)
{
return argument ?? throw new ArgumentNullException(paramName, message);
}
Reference:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/caller-argument-expression
With C# 11 and .NET 6.0 you can do this:
public bool DoSomething(string name)
{
ArgumentNullException.ThrowIfNull(name);
// Do your stuff, name is not null
}
ArgumentNullException.ThrowIfNull Method
It is actually possible to retrieve the argument name from the lambda expression without going through the Expression type. This is how it can be done:
static void SampleMethod(string arg1)
{
ThrowIfNull(() => arg1);
// continue to other normal stuff here...
}
public static void ThrowIfNull<T>(Func<T> lambda)
where T : class
{
if (lambda() == null)
{
throw new ArgumentNullException(lambda.Target.GetType().GetFields()[0].Name);
}
}