scottksmith95 / LINQKit

LINQKit is a free set of extensions for LINQ to SQL and Entity Framework power users.
MIT License
1.63k stars 163 forks source link

ExpressionVisitor.VisitConditional might fail if used in polymorphism #169

Open Azkarell opened 2 years ago

Azkarell commented 2 years ago

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

TheConstructor commented 1 year ago

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 ConditionalExpressions and enforces the Type of both expressions to be equal.