3

我有几个类派生自抽象类 A - A1、A2、A3 等。

我需要使用它们自己的鉴别器使用如下代码将这些类注册到 BsonClassMap:

BsonClassMap.RegisterClassMap<A1>(cm =>
{
    cm.AutoMap();
    cm.SetDiscriminator(discriminator)
});

由于将来我会有更多这样的课程,我想使用反射来做到这一点:

foreach (var type in Assembly.GetAssembly(typeof(A))
                             .GetTypes().Where(t => t.IsClass 
                                        && !t.IsAbstract 
                                        && t.IsSubclassOf(typeof(A))))
{
    var discriminator = type.GetField("Discriminator")
                            .GetRawConstantValue()
                            .ToString();

    var method = typeof(BsonClassMap).GetMethods()
                        .FirstOrDefault(m => m.IsGenericMethod 
                                             && m.Name == "RegisterClassMap");
    if (method == null) continue;
    var generic = method.MakeGenericMethod(type);
    generic.Invoke(this, null);
}

我怎样才能将这样的 lambda 表达式传递给这个函数?

cm =>
{
    cm.AutoMap();
    cm.SetDiscriminator(discriminator)
});

我找到了很多关于如何调用泛型方法的描述,但无法让它工作。

4

2 回答 2

4

除了@aL3891 发布的答案之外,我还模拟了一个简单的例子来说明我如何称呼它:

在这种情况下,SampleClass是代表BsonClassMap, 并且AbstractClass代表A

class Program
{
    static void Main(string[] args)
    {
        SampleClass.Foo<int>(param =>
            {

            });

        var discoveredTypes = new List<Type>
        {
            typeof(DerivedOne),
            typeof(DerivedTwo),
            typeof(DerivedThree)
        };

        foreach (var type in discoveredTypes)
        {
            var methodType = typeof(Program).GetMethods().FirstOrDefault(x => x.Name == "CreateMethod").MakeGenericMethod(type);

            var method = methodType.Invoke(null, null);

            var staticMethod = typeof(SampleClass).GetMethods().FirstOrDefault(x => x.Name == "Foo").MakeGenericMethod(type);

            staticMethod.Invoke(null, new object[] { method });
        }

        Console.ReadKey();
    }

    public static Action<T> CreateMethod<T>()
    {
        return new Action<T>((param) =>
            {
                Console.WriteLine("This is being invoked with type: " + typeof(T).Name);
            });
    }
}

public abstract class AbstractClass { }

public class DerivedOne : AbstractClass { }
public class DerivedTwo : AbstractClass { }
public class DerivedThree : AbstractClass { }

public class SampleClass
{
    public static void Foo<TGenericType>(Action<TGenericType> setupMethod)
        where TGenericType : new()
    {
        TGenericType instance = new TGenericType();

        setupMethod(instance);
    }
}

问题是您正试图从运行时声明转到编译时泛型,因此只需制作一个工厂风格的方法就可以很容易地调用来为您构造委托。中的CreateMethod方法Program将参与制作您的 lambda 表达式,然后您可以以BsonClassMap这种方式调用静态方法。

于 2013-10-10T18:04:15.573 回答
3

There are two parts to this question,

To pass a lambda to this method you simply pass it in an array as the second argument to the Invoke call. generic.Invoke(this, new object[]{foo});

However, the problem now is how do you get a object containing a lambda? This doesn't work var l = () => {...}, so whats the deal?

Well lambdas in c# can have two different types. They can be a a delegate (Func<...>or Action<..> or they can be an expression Expression<Func<...>>

What it actually ends up being depends on what you assign it to, or rather what the compiler infers it to be. So what you have to write to get an expression is Expression<Func<int>> e = () => 3;

Now you can pass e into your invoke call (provided that the expression types match up of course)

If this code is entirely generic, one solution might be to have a helper method that actually returns the expression you pass in:

public Action<T> GetMyDelegate<T>() where T: A{
  return (T cm) => {
    cm.AutoMap();
    cm.SetDiscriminator(discriminator)
  };
}

Also note that you can initialize a delegate such as Action with a method name:

 public void Method1() {
   var a = new Action(Method2);
 }

 public void Method2()
 {  }

You can also create a delegate from a MethodInfo, say if different subtypes of A have their own init method that you find with reflection: http://msdn.microsoft.com/en-us/library/53cz7sc6.aspx

于 2013-10-10T18:00:32.327 回答