如何指定从表达式树方法返回的对象?

时间:2011-02-07 17:21:13

标签: .net expression-trees

我正在尝试使用返回对象的表达式树创建方法,但我无法弄清楚如何实际指定要返回的对象。我试过阅读this,但实际上似乎没有在任何地方指定返回值。

我已完成所有作业和东西,但如何指定从使用表达式树创建的方法返回的对象?

编辑:这些是v4表达式树,我试图创建的方法是这样的:

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

3 个答案:

答案 0 :(得分:27)

在返回现有参数或变量的情况下,有一种更简单的方法可以做到这一点。块表达式中的最后一个语句成为返回值。您可以在最后再次包含ParameterExpression以使其返回。

假设你的结构是这样的:

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

然后你的代码看起来像这样:

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();

测试它是否有效:

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

值得一提的是,如果StructType是一个结构,这个例子是有效的。如果它是一个类,你只需调用构造函数并在BlockExpression中初始化structVar。

答案 1 :(得分:20)

显然returnGotoExpression您可以使用Expression.Return工厂方法创建的{{3}}。你需要在最后创建一个标签来跳转到它。像这样:

// 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);

标签目标的类型和goto表达式必须匹配。由于标签目标具有类型,因此标签表达式必须具有默认值。

答案 2 :(得分:15)

我发现了一些暗示(一种情况)或实际状态(另一种情况)从表达式返回值的源可以简单地通过使用与所讨论的值对应的参数表达式来结束该块来完成,因为来自块的最后一个值表达式变为其返回值。据报道,Expression.Return工厂适用于更复杂的情况,其中一个从代码块的中间返回。

换句话说,如果块中的最后一个表达式只是objExpression,那就足够了。我认为,如果使用Return方法和标签解构所有业务,实际发生的是objExpression基本上传递给标签(在块的末尾)并离开那里,就像你消除returnExpression一样和returnLabel并简单地用objExpression结束。

不幸的是,我实际上无法自己测试这个。