Comment spécifier l'objet à renvoyer depuis une méthode d'arborescence d'expression?

.net expression-trees

Question

J'essaie de créer une méthode à l'aide d'un arbre d'expression qui renvoie un objet, mais je ne vois pas comment spécifier l'objet à renvoyer. J'ai essayé de lire ceci , mais la valeur de retour ne semble pas être spécifiée nulle part.

J'ai toutes les assignations et tout le reste, mais comment puis-je spécifier l'objet à renvoyer à partir d'une méthode créée en utilisant des arbres d'expression?

EDIT: ce sont des arbres d’expression v4, et la méthode que j’essaie de créer fait quelque chose comme ceci:

private object ReadStruct(BinaryReader reader) {
    StructType obj = new StructType();
    obj.Field1 = reader.ReadSomething();
    obj.Field2 = reader.ReadSomething();
    //...more...
    return obj;
}

Réponse acceptée

Apparemment, un return est une GotoExpression que vous pouvez créer avec la méthode d'usine Expression.Return . Vous devez créer une étiquette à la fin pour y accéder rapidement. Quelque chose comme ça:

// an expression representing the obj variable
ParameterExpression objExpression = ...;

LabelTarget returnTarget = Expression.Label(typeof(StructType));

GotoExpression returnExpression = Expression.Return(returnTarget, 
    objExpression, typeof(StructType));

LabelExpression returnLabel = Expression.Label(returnTarget, defaultValue);

BlockExpression block = Expression.Block(
    /* ... variables, all the other lines and... */,
    returnExpression,
    returnLabel);

Les types de libellé cible et d’expression goto doivent correspondre. Comme la cible de l'étiquette a un type, l'expression de l'étiquette doit avoir une valeur par défaut.


Réponse populaire

Il existe un moyen beaucoup plus simple de le faire dans les cas où un paramètre ou une variable existant est renvoyé. La dernière instruction dans une expression de bloc devient la valeur de retour. Vous pouvez à nouveau inclure ParameterExpression à la fin pour le renvoyer.

En supposant que votre structure est comme ceci:

public struct StructType
{
    public byte Field1;
    public short Field2;
}

Ensuite, votre code ressemblerait à ceci:

var readerType = typeof(BinaryReader);
var structType = typeof(StructType);
var readerParam = Expression.Parameter(readerType);
var structVar = Expression.Variable(structType);

var expressions = new List<Expression>();

expressions.Add(
    Expression.Assign(
        Expression.MakeMemberAccess(structVar, structType.GetField("Field1")),
        Expression.Call(readerParam, readerType.GetMethod("ReadByte"))
        )
    );

expressions.Add(
    Expression.Assign(
        Expression.MakeMemberAccess(structVar, structType.GetField("Field2")),
        Expression.Call(readerParam, readerType.GetMethod("ReadInt16"))
        )
    );

expressions.Add(structVar); //This is the key. This will be the return value.

var ReadStruct = Expression.Lambda<Func<BinaryReader, StructType>>(
    Expression.Block(new[] {structVar}, expressions),
    readerParam).Compile();

Vérifiez que cela fonctionne:

var stream = new MemoryStream(new byte[] {0x57, 0x46, 0x07});
var reader = new BinaryReader(stream);
var struct1 = ReadStruct(reader);

Il convient de mentionner que cet exemple fonctionne si StructType est une structure. S'il s'agit d'une classe, vous appelez simplement le constructeur et initialisez structVar en premier dans BlockExpression.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow