LINQKit
LINQKit copied to clipboard
ExpressionVisitor.VisitConditional might fail if used in polymorphism
Given following code snippets
public interface ICommon {}
public class ModelA: ICommon
{
}
public class ModelB: ICommon
{
}
public class Data {}
public static class Converter
{
public static Expression<Func<Data, ICommon>> ToCommonA()
{
return data => new ModelA();
}
public static Expression<Func<Data, ICommon>> ToCommonB()
{
return data => new ModelB();
}
public static Expression<Func<Data, ICommon>> Conditional()
{
Random r = new Random();
return model => 10 > r.Next(20) ? ToCommonA().Invoke(model) : ToCommonB().Invoke(model);
}
public static void Test()
{
Console.WriteLine(Conditional().Expand().ToString());
}
}
Calling the Test method will throw an ArgumentException in Expression.Conditional because ifTrue.Type != ifFalse.Type. this can be prevented by casting the modelA/modelB to ICommon but should probably be fixed in the library, if i have the time i might even look into creating a pull request. Checking if the return type matches if not try to cast / check if it is assignable to the original type (which it should be or else the expression would not have been created in the first place).
#182 likely solves this for everything more recent then .NET 3.5 as ConditionalExpression.Update
explicitly initializes the Type
of the new ConditionalExpression
to the old Type
.
Currently Expression.Condition(test, ifTrue, ifFalse)
is used, which (in .NET 3.5) seems to be the only canon way to create ConditionalExpression
s and enforces the Type
of both expressions to be equal.
- For > .NET 3.5
- using the bundled ExpressionVisitor (#182),
- calling
ConditionalExpression.Update
yourself or - using the 'new' (.NET 4.0; .NET Standard 1.0)
Expression.Condition(test, ifTrue, ifFalse, type)
,
likely each would solve the problem.
- For .NET 3.5 it seems you can only compare types and add converts as needed.