2015-01-15 52 views
0

我正在尋找一種很好的方法來在訪問propertys getter和setter時自動檢查訪問權限。處理每個獲取或設置的對象屬性

這只是出於好奇和實驗目的,所以表現並不重要。

一種方法,我發現如下(例子僅僅是干將):

public class DynamicPropertyClass : DynamicObject 
{ 
    /// <summary> 
    /// I want this to work for a default auto-property 
    /// </summary> 
    public string TestString { get; set; } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     if (StaticSecurityContext.CheckSecurityCondition(binder.GetType(), binder.Name)) 
     { 
      return base.TryGetMember(binder, out result); 
     } 
     else 
     { 
      throw new SecurityException(); 
     } 
    } 
} 

使用動態對象中止,如果安全條件沒有給出。 這種方法的問題是,TryGetMember方法無法處理該類上實際存在的屬性。 所以這種方法迫使我只處理代碼中實際不存在的屬性。

正如您所看到的,動態功能與我的方法無關。 我想要在代碼中編寫的屬性上進行類似的工作,動態功能不必受支持。

那麼,有沒有另一種方法,可能在C#中,沒有應用每個屬性的屬性或添加自定義代碼的getters和setter?

+1

您是否嘗試過使用組合物?換句話說,不要定義與TryGetMember相同類型的屬性 - 而是傳遞一個具有屬性的對象,並在通過安全條件後通過反射訪問這些屬性。 – 2015-01-15 15:28:38

+2

有時間看看面向方面的編程和PostSharp? http://doc.postsharp.net/location-interception – 2015-01-15 15:32:07

+0

使用反射來獲取所調用的屬性,並在每個屬性上使用get/set包裝將允許您將所有這些包裝在一個地方並處理返回值和錯誤拋出。 – Franck 2015-01-15 15:33:47

回答

0

這是一個老問題,但我認爲這很有趣,因爲貢獻了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); 
    } 
}