2011-08-05 42 views
0

說我有一些像這樣的方法:使用Expression API,有沒有辦法將Func <T>與另一個「組合」?

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

有沒有我可以使用Expression API,有效地注入一些代碼在傳遞Func運行的代碼之前要運行什麼辦法?意思是,在我的方法中,我不會實際執行Func,而是將其分配給一個將調用Func的對象的某個屬性。我只想在運行代碼之前運行一些代碼。此外,我的代碼是否可以從Func「返回」,以便傳入的代碼永遠不會運行?

編輯:好的,我擔心這還不夠。這是我想要做的。使用Moles,你可以將你的代碼中的任何呼叫存檔。所以說,我有一個調用像這樣一個靜態方法,一些不可測代碼:

FileSystem.ReadAllText(string fileName); 

痣會創建一個存根/摩爾對象(無論術語),我就可以使用存根出的方法,所以當我的代碼調用ReadAllText,它會叫我的存根:

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

非常酷的東西,但是我想這種想法擴展,這樣我可以用它類同一個典型的模擬框架(如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); 

將設置痣委託無論是進去時,我想先「注入」一些代碼,讓我可以看看有哪些正在傳遞的價值觀,我可以添加一些數據字典的一些跟蹤方法調用的計數等

希望這是現在更有意義......

+2

目前還不清楚表達式API的用途 - 您已經提供了方法簽名,但僅此而已。你已經討論過將'Func '分配給某個屬性,但是這並不需要使用表達式API ...請給我們更多的信息。 –

+0

@Jon Skeet:看編輯。讓我知道你是否需要更多的澄清。 – BFree

回答

3

何不你是否在將它分配給財產之前包裝它?

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

哈哈哈談談過度沉迷....哇.... – BFree

相關問題