2

動的式ビルダーを作成し、'like' 関数を実装しようとしています。独自の関数を作成する前に、既存の関数を検索し、必要に近い関数を見つけました。いくつかの実験の後、文字列以外の型に対して実行することができませんでした。

タイプのパラメーターを渡すと、次のintエラーが発生します。

型 'System.String' で宣言されたメソッド 'System.String ToString()' は、型 'System.Int32' のインスタンスで呼び出すことはできません

私のコードは次のようになります。

private static MethodCallExpression GetLowerCasePropertyAccess(MemberExpression propertyAccess)
{
    //return Expression.Call(Expression.Call(propertyAccess, "ToString", new Type[0]), typeof(string).GetMethod("ToLower", new Type[0]));
    return Expression.Call(Expression.Call(propertyAccess, typeof(string).GetMethod("ToString", System.Type.EmptyTypes)), typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
}

private static readonly MethodInfo ContainsMethod = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });

public static Expression<Func<T, bool>> Create<T>(string propertyName, ComparisonOperators comparisonOperator, dynamic comparedValue1, dynamic comparedValue2 = null)
{
    ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "x");
    MemberExpression memberExpression = Expression.MakeMemberAccess(parameterExpression, typeof(T).GetProperty(propertyName));
    ConstantExpression constantExpression = Expression.Constant(comparedValue1, comparedValue1.GetType());
    Expression expressionBody = null;

    switch (comparisonOperator)
    {
        ...

        case ComparisonOperators.Contains:
            //var indexOf = Expression.Call(memberExpression, "IndexOf", null, Expression.Constant(comparedValue1, typeof(string)), Expression.Constant(StringComparison.InvariantCultureIgnoreCase));
            //expressionBody = Expression.GreaterThanOrEqual(indexOf, Expression.Constant(0));
            expressionBody = Expression.Call(GetLowerCasePropertyAccess(memberExpression), ContainsMethod, Expression.Constant(comparedValue1.ToLower()));
            break;
    }

    return Expression.Lambda<Func<T, bool>>(expressionBody, new ParameterExpression[] { parameterExpression });
}
4

3 に答える 3

0

あなたが何をしているのか完全に理解しているかどうかはわかりませんが、あなたのエラーは次の行が原因だと思います:

return Expression.Call(Expression.Call(propertyAccess, typeof(string).GetMethod("ToString", System.Type.EmptyTypes)), typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));

これは常に型のToStringメソッドを呼び出そうとstringします。したがって、Int32プロパティを使用しようとするとString.ToString()、 を呼び出そうとしています。 の実装はToString()型によって異なり、2 つの実装は必ずしも互換性があるとは限らないためです。あなたが見ている例外を取得します:

Method 'System.String ToString()' declared on type 'System.String' cannot be called with instance of type 'System.Int32'

あなたがしているように見えることから、これがあなたが求めているものかもしれないと思います:

return Expression.Call(Expression.Call(propertyAccess, propertyAccess.Type.GetMethod("ToString", System.Type.EmptyTypes)), typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));

ToString(から取得したタイプで)の正しい実装を使用しますpropertyAccess.Type

于 2013-09-01T15:59:26.770 に答える
0

.ToStringエンティティへの Linq はメソッドをサポートしていません。数値を文字列に変換するには、SqlFunctions.StringConvertメソッドを使用する必要があります。コードを修正しました。like文字列と数値の列で実行できるようになりました。

private static Expression GetConvertToStringExpression(Expression e)
{
    // if property string - no cast needed
    // else - use SqlFunction.StringConvert(double?) or SqlFunction.StringConvert(decimal?);
    Expression strExpression = null;
    if (e.Type == typeof(string))
        strExpression = e;

    var systemType = Nullable.GetUnderlyingType(e.Type) ?? e.Type;

    if (systemType == typeof(int) 
        || systemType == typeof(long) 
        || systemType == typeof(double)
        || systemType == typeof(short)
        || systemType == typeof(byte)) // continue
    {
        // cast int to double
        var doubleExpr = Expression.Convert(e, typeof (double?));
        strExpression = Expression.Call(StringConvertMethodDouble, doubleExpr);
    }

    if (systemType == typeof (decimal))
    {
        // call decimal version of StringConvert method
        // cast to nullable decimal
        var decimalExpr = Expression.Convert(e, typeof (decimal?));
        strExpression = Expression.Call(StringConvertMethodDecimal, decimalExpr);
    }

    return strExpression;
}

private static MethodCallExpression GetLowerCasePropertyAccess(Expression propertyAccess)
{
    var stringExpression = GetConvertToStringExpression(propertyAccess);
    if (stringExpression == null)
        throw new Exception(string.Format("Not supported property type {0}", propertyAccess.Type));

    return Expression.Call(stringExpression,
        typeof (string).GetMethod("ToLower", Type.EmptyTypes));
}

private static readonly MethodInfo StringConvertMethodDouble = typeof (SqlFunctions).GetMethod("StringConvert",
    new Type[] {typeof (double?)});
private static readonly MethodInfo StringConvertMethodDecimal = typeof(SqlFunctions).GetMethod("StringConvert",
    new Type[] { typeof(decimal?) });
于 2013-09-01T22:52:06.403 に答える