Konvertierungsproblem mit Expression Trees

c# expression-trees

Frage

Ich habe eine Ausdruckbaumfunktion von einer vorhergehenden SO Frage. Es ermöglicht grundsätzlich die Umwandlung einer Datenzeile in eine bestimmte Klasse.

Dieser Code funktioniert einwandfrei, es sei denn, Sie befassen sich mit Datentypen, die größer oder kleiner sein können (z. B. Int32 / Int64).

Der Code Int64 eine ungültige Cast-Ausnahme aus, wenn von Int64 zu Int32 wenn der Wert in ein Int32 (z. B. Zahlen in 3000).

Sollte ich?

  1. Versuchen Sie, dies im Code zu beheben? (Wenn ja, irgendwelche Hinweise?)
  2. Belassen Sie den Code so wie er ist.

    private Func<SqlDataReader, T> getExpressionDelegate<T>()
    {
        // hang on to row[string] property 
        var indexerProperty = typeof(SqlDataReader).GetProperty("Item", new[] { typeof(string) });
    
        // list of statements in our dynamic method
        var statements = new List<Expression>();
    
        // store instance for setting of properties
        ParameterExpression instanceParameter = Expression.Variable(typeof(T));
        ParameterExpression sqlDataReaderParameter = Expression.Parameter(typeof(SqlDataReader));
    
        // create and assign new T to variable: var instance = new T();
        BinaryExpression createInstance = Expression.Assign(instanceParameter, Expression.New(typeof(T)));
        statements.Add(createInstance);
    
        foreach (var property in typeof(T).GetProperties())
        {
    
            // instance.MyProperty
            MemberExpression getProperty = Expression.Property(instanceParameter, property);
    
            // row[property] -- NOTE: this assumes column names are the same as PropertyInfo names on T
            IndexExpression readValue = Expression.MakeIndex(sqlDataReaderParameter, indexerProperty, new[] { Expression.Constant(property.Name) });
    
            // instance.MyProperty = row[property]
            BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
            statements.Add(assignProperty);
        }
    
        var returnStatement = instanceParameter;
        statements.Add(returnStatement);
    
        var body = Expression.Block(instanceParameter.Type, new[] { instanceParameter }, statements.ToArray());
    
        var lambda = Expression.Lambda<Func<SqlDataReader, T>>(body, sqlDataReaderParameter);
    
        // cache me!
        return lambda.Compile();
    }
    

Aktualisieren:

Ich habe jetzt aufgegeben und entschieden, dass es sich nicht lohnt. Von den Kommentaren unten bin ich soweit gekommen:

            if (readValue.Type != property.PropertyType)
            {
                BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(Expression.Call(property.PropertyType, "Parse", null, new Expression[] { Expression.ConvertChecked(readValue, typeof(string)) }), property.PropertyType));
                statements.Add(assignProperty);
            }
            else
            {
                // instance.MyProperty = row[property]
                BinaryExpression assignProperty = Expression.Assign(getProperty, Expression.Convert(readValue, property.PropertyType));
                statements.Add(assignProperty);
            }

Ich glaube nicht, dass ich zu weit weg war, fühle mich frei, es zu beenden und die Antwort zu posten, wenn du es herausgefunden hast :)

Akzeptierte Antwort

Sie könnten versuchen, es zu beheben, indem Sie "convert checked" vor dem Zuweisen verwenden, dh mit Expression.ConvertChecked für den Wert anstelle von Expression.Convert .

Konnte es jetzt nicht versuchen, aber das sollte sich um den Fall kümmern, den Sie beschreiben ...

EDIT - wie Kommentar könnte dies ein Box-Problem sein:

In diesem Fall könnten Sie versuchen, Expression.TypeAs oder Expression.Unbox für die Konvertierung zu verwenden oder Expression.Call zum Aufrufen einer Methode für die Konvertierung zu verwenden. Ein Beispiel für die Verwendung von Call finden Sie unter http://msdn.microsoft.com. com / de-de / library / bb349020.aspx


Beliebte Antwort

Was Sie zu erstellen versuchen, ist eigentlich viel komplizierter, wenn Sie 100% der Primitiven in .NET und SQL unterstützen wollen.

Wenn Sie sich nicht für einige der Randfälle interessieren (NULL-fähige Typen, Enums, Byte-Arrays usw.), gibt es zwei Tipps, um Sie zu 90% zu bringen:

Verwenden Sie nicht den Indexer für IDataRecord, es gibt ein Objekt zurück, und das Boxing / Unboxing führt zu Leistungseinbußen. Beachten Sie stattdessen, dass IDataRecord die Methode Get [typeName] enthält. Diese existieren für alle .NET primitiven Typen (Achtung: GetFloat, nicht GetSingle, große Belästigung).

Sie können IDataRecord.GetFieldType verwenden, um herauszufinden, welche Get-Methode Sie für eine bestimmte Spalte aufrufen müssen. Sobald Sie das haben, können Sie mit Expression.Convert den DB-Spaltentyp auf den Typ der Zieleigenschaft umstellen (falls sie unterschiedlich sind). Dies wird für einige der oben aufgeführten Randfälle fehlschlagen, für die Sie benutzerdefinierte Logik benötigen.



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow