5

我想调用一个需要这样一个参数的方法:

Expression<Func<sometype, 'a>> expr

我需要在运行时构造这个参数,因为之前我不知道匿名类型会是什么样子;它可以有任意数量的字段:

x => new { a=x.a, b=x.b, c=x.c, etc... }

我可以在运行时创建一个类型,它与所需的匿名类型具有相同的“签名”(这是正确的词吗?),但问题是:如何在运行时从中构造这个 lambda 表达式?特别是 Expression.New 困扰着我,因为我需要传递一个 constructorInfo 给它,我必须从现有类型中获取(它确实可以是匿名类型,但我不能在运行时创建匿名类型。或者是否存在一种方法吗?)。

更新(评论中要求的一些上下文)

我要调用的方法是:

DependentNavigationPropertyConfiguration.HasForeignKey<TKey>(Expression<Func<TDependentEntityType, TKey>> foreignKeyExpression)

我想这样做的原因是自动使从某个基类继承的实体的导航属性在外键中包含该基类的键。因为一个实体可以有多个任意类型的键字段,类型 TKey 只有在运行时我才知道。

4

3 回答 3

15

使用单独的方法:

public static void Main()
{
    var myExpression = Express(str => new { 
        String = str, 
        Length = str.Length 
    });

    // We can compile/use it as well...
    var compiledExpression = myExpression.Compile();
    var anonymousOutput = compiledExpression("Input String");

    Console.WriteLine(anonymousOutput.String); // Output: Input String
    Console.WriteLine(anonymousOutput.Length); // Output: 12

    Debug.WriteLine(myExpression); // Output: "str => new <>f__AnonymousType0`2(String = str, Length = str.Length)"
    Console.ReadLine();
}


static Expression<Func<String, T>> Express<T>(Expression<Func<String, T>> expression)
{
    return expression;
}

但是请注意,String必须预先知道起始类型(在我的示例中)。

更新

由于听起来您想要做的是动态创建一个类型,所以我将给您一个简单的示例来说明如何做到这一点。

public static void Main()
{
        // Create an anonymous type with two fields
    Type myAnonymousType = CreateNewType<String, Int32>();
    dynamic myAnon = Activator.CreateInstance(myAnonymousType);

    myAnon.FieldA = "A String";
    myAnon.FieldB = 1234;


    Console.WriteLine(myAnon.FieldA); // Output : "AString"
    Console.WriteLine(myAnon.FieldB); // Output : 1234
    Console.ReadLine();
}

public static Type CreateNewType<TFieldTypeA, TFieldTypeB>()
{
    // Let's start by creating a new assembly
    AssemblyName dynamicAssemblyName = new AssemblyName("MyAsm");
    AssemblyBuilder dynamicAssembly = AssemblyBuilder.DefineDynamicAssembly(dynamicAssemblyName, AssemblyBuilderAccess.Run);
    ModuleBuilder dynamicModule = dynamicAssembly.DefineDynamicModule("MyAsm");

    // Now let's build a new type
    TypeBuilder dynamicAnonymousType = dynamicModule.DefineType("MyAnon", TypeAttributes.Public);

    // Let's add some fields to the type.
    FieldInfo dynamicFieldA = dynamicAnonymousType.DefineField("FieldA", typeof(TFieldTypeA), FieldAttributes.Public);
    FieldInfo dynamicFieldB = dynamicAnonymousType.DefineField("FieldB", typeof(TFieldTypeB), FieldAttributes.Public);

    // Return the type to the caller
    return dynamicAnonymousType.CreateType();
}

如您所见,这有点复杂。但是,如果您想进一步研究该主题,请务必参考Reflectoin.Emit

于 2013-05-30T14:00:30.537 回答
3

匿名类型是编译器功能。如果您没有让编译器在编译时创建它们,那么您将不得不使用元编程——要么TypeBuilder或也许CSharpCodeProvider. 使用元组可能会更好——至少它们很容易创建(你可以Tuple.Create很容易地使用)。

至于表达;我建议将其输入为Expression<Func<sometype, object>>- 这适用于任何配方。检查代码Expression当然可以查看实际类型是什么。

于 2013-05-30T14:00:59.080 回答
-8

你可以这样做

context.Students.Join(context.Courses, a => a.Course_id, b => b.Course_id, (a, b) => new { Student= a, Course= b }).Where(x => x.Student_id == studentId)
      .Select(y => new
      {
         StudentId = y.Student.StudentId,
         RegistrationNumber = y.Student.RegNo,
         Name = y.Student.Name,
         Coursename = y.Course.Name
      }).ToList();
于 2014-01-06T05:35:04.283 回答