這是一個老問題,但我認爲這很有趣,因爲貢獻了DynamicProxy沒有提及。 您也可以使用DynamicProxy nuget package from Castle.Core。
您可以攔截對所有類的虛擬屬性的Get和Set方法的調用。
I have written a Gist explaining the concept,跟蹤 當屬性被訪問和設置。
這是Interceptor的樣子。
public class GetSetInterceptor : Interceptor
{
protected override void ExecuteBefore(IInvocation invocation)
{
}
protected override void ExecuteAfter(IInvocation invocation)
{
if(invocation.Method.Name.StartsWith("get_") || invocation.Method.Name.StartsWith("set_"))
{
var target = invocation.InvocationTarget as TrackedObject;
if(target == null)
{
return;
}
var methodInvoked = invocation.Method.Name.Split("_");
switch (methodInvoked[0])
{
case "get":
target.AddEvent(EventType.Get, methodInvoked[1], invocation.ReturnValue);
break;
case "set":
target.AddEvent(EventType.Set, methodInvoked[1], invocation.Arguments[0]);
break;
}
}
}
}
代理的創建,像這樣做:
ProxyGenerator generator = new ProxyGenerator();
var tracked = generator.CreateClassProxy<TrackedClass>(new GetSetInterceptor());
的TrackedClass必須具有虛擬性質:
public class TrackedClass : TrackedObject
{
public virtual string SomeContent { get; set; }
public virtual int SomeInt { get; set; }
}
測試是在這裏(使用的xUnit):
public class GetterSetterInterceptorTests
{
[Fact]
public void SuccessFullyRegisterGetAndSetEvents()
{
ProxyGenerator generator = new ProxyGenerator();
var tracked = generator.CreateClassProxy<TrackedClass>(new GetSetInterceptor());
tracked.SomeContent = "some content";
Assert.Single(tracked.GetEvents());
var eventAfterSomeContentAssigned = tracked.GetEvents().Last();
Assert.Equal(EventType.Set, eventAfterSomeContentAssigned.EventType);
Assert.Equal("some content", eventAfterSomeContentAssigned.Value);
Assert.Equal("SomeContent", eventAfterSomeContentAssigned.PropertyInfo.Name);
tracked.SomeInt = 1;
Assert.Equal(2, tracked.GetEvents().Count);
var eventAfterSomeIntAssigned = tracked.GetEvents().Last();
Assert.Equal(EventType.Set, eventAfterSomeContentAssigned.EventType);
Assert.Equal(1, eventAfterSomeIntAssigned.Value);
Assert.Equal("SomeInt", eventAfterSomeIntAssigned.PropertyInfo.Name);
var x = tracked.SomeInt;
Assert.Equal(3, tracked.GetEvents().Count);
var eventAfterSomeIntAccessed = tracked.GetEvents().Last();
Assert.Equal(EventType.Get, eventAfterSomeIntAccessed.EventType);
Assert.Equal(1, eventAfterSomeIntAccessed.Value);
Assert.Equal("SomeInt", eventAfterSomeIntAccessed.PropertyInfo.Name);
}
}
您是否嘗試過使用組合物?換句話說,不要定義與TryGetMember相同類型的屬性 - 而是傳遞一個具有屬性的對象,並在通過安全條件後通過反射訪問這些屬性。 – 2015-01-15 15:28:38
有時間看看面向方面的編程和PostSharp? http://doc.postsharp.net/location-interception – 2015-01-15 15:32:07
使用反射來獲取所調用的屬性,並在每個屬性上使用get/set包裝將允許您將所有這些包裝在一個地方並處理返回值和錯誤拋出。 – Franck 2015-01-15 15:33:47