I lied! =)
I did find one issue with the latest commit when the value actually is null, but I think I've found a fix.
First, let's update the unit test to include some tests where the value is actually null. I added a Length property to the Fact (which as a nullable int that's null), and I added another "Argument3" that's null, using your handy new overload:
public void NullableType()
var expression = new CompiledExpression()
TypeRegistry = new TypeRegistry()
int? argument1 = 5;
var argument2 = new Fact()
Count = 5,
Length = null
expression.TypeRegistry.RegisterSymbol("Argument1", argument1, typeof(int?));
expression.TypeRegistry.RegisterSymbol("Argument3", null, typeof(int?));
expression.StringToParse = "Argument1 != null";
expression.StringToParse = "Argument2.Count != null";
expression.StringToParse = "Argument2.Length != null";
expression.StringToParse = "Argument3 != null";
So what happens if we run this in the latest commitment, is the ones where the symbols aren't null work right, and the ones were the symbols ARE null (the last two cases above) get converted to "0 != null" and then evaluate to true, when they should
have been false.
I'm no expert in this, but I traced it to the new NullLiteralConversion() method. The overload to select the constructor used for Activator.CreateInstance ends up passing the underlying type (which doesn't have a null value, and ends up using the default, in
this case 0 for int). I fixed it by using the overload that says "use the parameterless constructor for Nullable<whatever>":
// 6.1.5 Null literal conversions
//An implicit conversion exists from the null literal to any nullable type. This conversion produces the null value (§4.1.10) of the given nullable type.
public static Expression NullLiteralConverion(Expression dest, Expression src)
if (src.NodeType == ExpressionType.Constant
&& src.Type == typeof(object)
&& ((ConstantExpression)src).Value == null
&& Nullable.GetUnderlyingType(dest.Type) != null)
var value = Activator.CreateInstance(dest.Type);
return Expression.Constant(value, dest.Type);
And all tests seem to now pass. Hope this helps!