使用表达式API,是否有一种方法来“组合”?Func< T>与另一个

本文关键字:组合 Func 另一个 方法 一种 API 表达式 是否 | 更新日期: 2023-09-27 18:04:42

假设我有这样的方法:

public void Method<T>(Func<T> func)
{
...
}

是否有任何方法,我可以使用Expression API,并有效地注入一些代码运行之前,在Func传递的代码运行?意思是,在我的方法中,我不会实际执行Func,而是给它分配一个对象的一些属性,它将调用Func。我只是想让一些代码在传入的代码运行之前运行。此外,我的代码是否有可能从Func"返回",以便传递的代码永远不会运行?

编辑:好吧,我担心这还不够。这就是我要做的。使用mole,您可以在代码中删除任何调用。假设我有一些不可测试的代码,它调用了一个静态方法,像这样:

FileSystem.ReadAllText(string fileName);

mole将创建一个stub/mole对象(无论术语是什么),然后我可以使用它来stub方法,所以当我的代码调用ReadAllText时,它将调用我的stub:

MFileSytem.ReadAllTextString = s => return "content";

非常酷的东西,但是我试图扩展这个想法,这样我就可以使用它类似于一个典型的mock框架(如Moq),这样我就可以存根该方法只有当传入的参数是一个特定的值,或者可能验证一个方法只被调用一次等。以下是目前为止的内容:

还是非常非常粗糙!!

    public static class Extensions
    {
        public static void TestWithMoles<T, U, V>(this T item, Expression<Func<U, V>> expression, MolesDelegates.Func<U, V> stub)
        {
            var methodCallExpression = expression.Body as MethodCallExpression;
            if (methodCallExpression != null)
            {
                var method = methodCallExpression.Method;
                var returnType = method.ReturnType.Name;
                var assemblyName = method.DeclaringType.Assembly;
                var assmebly = GetMolesAssmeblyName(assemblyName.GetName().Name);
                var type = assmebly.GetTypes().FirstOrDefault(t => t.Name == "M" + method.DeclaringType.Name);
                var property = type.GetProperties(BindingFlags.Static | BindingFlags.Public).FirstOrDefault(p => p.Name == method.Name + returnType);
                property.SetValue(item, stub, null);
            }
        }
        private static Assembly GetMolesAssmeblyName(string assemblyName)
        {
            var entryAssembly = Assembly.GetExecutingAssembly();
            foreach (var assembly in entryAssembly.GetReferencedAssemblies())
            {
                if (assembly.Name == assemblyName)
                {
                    continue;
                }
                if (assembly.Name.Contains(assemblyName) && assembly.Name.Contains(".Moles"))
                {
                    return Assembly.Load(assembly.FullName);
                }
            }
            return null;
        }
    }
现在的想法是,如果我有一个这样的类:
public class TestReader
{
    public string Content { get; private set; }
    public void LoadFile(string fileName)
    {
        var content = FileSystem.ReadAllText(fileName);
        if (!content.StartsWith("test"))
        {
            throw new ArgumentException("invalid file");
        } 
        this.Content = content;
    }
}

我现在可以这样做:

    [TestMethod]
    [HostType("Moles")]
    public void CheckValidFilewithMoles()
    {
        //arrange
        var fileName = "test.txt";
        var content = "test";
        //act
        var test = new TestReader();
        test.TestWithMoles<TestReader, string, string>(s => FileSystem.ReadAllText(s), s =>
                                                                                            {
                                                                                                Assert.IsTrue(s == fileName);
                                                                                                return content;
                                                                                            });
        test.LoadFile(fileName);
        //assert
        Assert.AreEqual(content, test.Content);
    }

到目前为止还好,但是我还没有完成任何事情。我想做的是,在我的扩展方法中,当我这样做时:

            property.SetValue(item, stub, null);

将设置mole委托给传入的任何东西,我想事先"注入"一些代码,这样我就可以看到传入的值是什么,我可以向一些字典添加一些数据来跟踪方法调用的计数,等等。

使用表达式API,是否有一种方法来“组合”?Func< T>与另一个

为什么不在赋值给属性之前包装它呢?

Func<T> myProp = () => 
{ 
  //run your code here
  return func();
}