使用反射调用静态泛型方法传递 Lamba 作为参数

发布于 2024-12-17 06:37:30 字数 755 浏览 2 评论 0原文

是否可以通过反射编写以下代码?

    var fake = A.Fake<Foo>(
            o => o.WithArgumentsForConstructor(new[] { "Hello" }));

其中 o 是:

Action<IFakeOptionsBuilder<T>>

其中 WithArgumentsForConstructor 是:

IFakeOptionsBuilder<T> WithArgumentsForConstructor(IEnumerable<object> argumentsForConstructor);

Foo 类是:

class Foo
{
    public Foo(string s)
    {
    }
}

我所做的是:

object fake = typeof(A)
    .GetMethod("Fake", new Type[] { })
    .MakeGenericMethod(new[] { this.targetType })
    .Invoke(null, /* Here I need to pass the lambda. */);

Is it possible to write the following code via Reflection?

    var fake = A.Fake<Foo>(
            o => o.WithArgumentsForConstructor(new[] { "Hello" }));

Where o is:

Action<IFakeOptionsBuilder<T>>

Where WithArgumentsForConstructor is:

IFakeOptionsBuilder<T> WithArgumentsForConstructor(IEnumerable<object> argumentsForConstructor);

The Foo class is:

class Foo
{
    public Foo(string s)
    {
    }
}

What I did was:

object fake = typeof(A)
    .GetMethod("Fake", new Type[] { })
    .MakeGenericMethod(new[] { this.targetType })
    .Invoke(null, /* Here I need to pass the lambda. */);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蛮可爱 2024-12-24 06:37:30

是的,可以通过反思来做你建议的事情,但完全没有必要。自己定义一个静态方法会更简单,如下所示:

public static class MyClass
{
    public static T CreateFakeWithArgumentsForConstructor<T>(object[] argumentsForConstructor)
    {
        return A.Fake<T>(x => x.WithArgumentsForConstructor(argumentsForConstructor));
    }
}

现在只需使用反射调用此函数:

var method = typeof(MyClass).GetMethod("CreateFakeWithArgumentsForConstructor", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(new[] { theType });
method.Invoke(null, argumentsForConstructor);

Yes, it is possible to do what you suggest via reflection, however quite unnecessary. It would be simpler to define a static method yourself like this:

public static class MyClass
{
    public static T CreateFakeWithArgumentsForConstructor<T>(object[] argumentsForConstructor)
    {
        return A.Fake<T>(x => x.WithArgumentsForConstructor(argumentsForConstructor));
    }
}

Now simply call this function using reflection:

var method = typeof(MyClass).GetMethod("CreateFakeWithArgumentsForConstructor", BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(new[] { theType });
method.Invoke(null, argumentsForConstructor);
捶死心动 2024-12-24 06:37:30

如果我正确理解了这个问题,那么以下应该没问题:

Action<IFakeOptionsBuilder<Foo>> fakeOptionsBuilderAction = 
    o => o.WithArgumentsForConstructor(new[] { "", "" });

// You need the BindingFlags as Fake() is a static method:
object fake = typeof(A)
    .GetMethod("Fake", BindingFlags.Public | BindingFlags.Static)
    .MakeGenericMethod(new[] { typeof(Foo) })
    .Invoke(null, new object[] { fakeOptionsBuilderAction });

With Foo defied as:

class Foo
{
    public Foo(string one, string two)
    {
    }
}

If I've understood the question correctly, the following should be fine:

Action<IFakeOptionsBuilder<Foo>> fakeOptionsBuilderAction = 
    o => o.WithArgumentsForConstructor(new[] { "", "" });

// You need the BindingFlags as Fake() is a static method:
object fake = typeof(A)
    .GetMethod("Fake", BindingFlags.Public | BindingFlags.Static)
    .MakeGenericMethod(new[] { typeof(Foo) })
    .Invoke(null, new object[] { fakeOptionsBuilderAction });

With Foo defied as:

class Foo
{
    public Foo(string one, string two)
    {
    }
}
陌路黄昏 2024-12-24 06:37:30

最后! :)

困难的部分是,在运行时,我不知道类型,因此泛型不是一个选项(甚至在私有帮助器方法上也是如此)。

场景是能够做到这一点:

var fake = new Fake<Foo>(o => o.WithArgumentsForConstructor("Hello"));

这是我得到的解决方案:

private IEnumerable<object> argumentsForConstructor;

public object Invoke(IEnumerable<object> parameters)
{
    this.argumentsForConstructor = parameters;

    Type actionType = typeof(Action<>).MakeGenericType(
         typeof(IFakeOptionsBuilder<>).MakeGenericType(this.targetType));

    MethodInfo actionMethod = this.GetType()
        .GetMethod("SetArgumentsForConstructor", BindingFlags.Instance | BindingFlags.NonPublic)
        .MakeGenericMethod(new[] { this.targetType });

    Delegate action = Delegate.CreateDelegate(actionType, this, actionMethod);

    Type fake = typeof(Fake<>).MakeGenericType(this.targetType);
    ConstructorInfo ctor = (from ci in fake.GetConstructors(BindingFlags.Instance | BindingFlags.Public)
                            from pi in ci.GetParameters()
                            where pi.ParameterType == actionType
                            select ci).First();

    return ctor.Invoke(new[] { action });
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method is used by Reflection. It describes the method that is passed in the Action<IFakeOptionsBuilder<T>> overload of the Fake<T> constructor.")]
private void SetArgumentsForConstructor<T>(IFakeOptionsBuilder<T> o)
{
    if (typeof(T).IsInterface)
    {
        return;
    }

    o.WithArgumentsForConstructor(this.argumentsForConstructor);
}

像魅力一样工作。 :)

Finally! :)

The difficult part was that, on runtime, I don't know the types so generics is not an option (not even on the private helper method).

The scenario is to be able to do this:

var fake = new Fake<Foo>(o => o.WithArgumentsForConstructor("Hello"));

Here is the solution I got:

private IEnumerable<object> argumentsForConstructor;

public object Invoke(IEnumerable<object> parameters)
{
    this.argumentsForConstructor = parameters;

    Type actionType = typeof(Action<>).MakeGenericType(
         typeof(IFakeOptionsBuilder<>).MakeGenericType(this.targetType));

    MethodInfo actionMethod = this.GetType()
        .GetMethod("SetArgumentsForConstructor", BindingFlags.Instance | BindingFlags.NonPublic)
        .MakeGenericMethod(new[] { this.targetType });

    Delegate action = Delegate.CreateDelegate(actionType, this, actionMethod);

    Type fake = typeof(Fake<>).MakeGenericType(this.targetType);
    ConstructorInfo ctor = (from ci in fake.GetConstructors(BindingFlags.Instance | BindingFlags.Public)
                            from pi in ci.GetParameters()
                            where pi.ParameterType == actionType
                            select ci).First();

    return ctor.Invoke(new[] { action });
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method is used by Reflection. It describes the method that is passed in the Action<IFakeOptionsBuilder<T>> overload of the Fake<T> constructor.")]
private void SetArgumentsForConstructor<T>(IFakeOptionsBuilder<T> o)
{
    if (typeof(T).IsInterface)
    {
        return;
    }

    o.WithArgumentsForConstructor(this.argumentsForConstructor);
}

Works like a Charm. :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文