处理对对象属性的每个获取或设置调用
Handle every get or set call to objects properties
我正在寻找一种在访问 属性s getter 和 setter 时自动检查访问权限的好方法。
这只是出于好奇和实验目的,所以性能并不重要。
我发现的一种方法如下(示例仅适用于 getters):
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();
}
}
}
如果未提供安全条件,则使用动态对象中止。
这种方法的问题是 class 上实际存在的属性不会由 TryGetMember 方法处理。
所以这种方法迫使我只处理代码中实际不存在的属性。
如您所见,动态功能与我的方法并不相关。
我想要一些类似的东西来处理我用代码编写的属性,不需要支持动态功能。
那么,是否有另一种方法可以在 c# 中使用,而不在每个 属性 上应用属性或向 getter 和 setter 添加自定义代码?
您可以使用代理模式。
它存在很多由 AOP 框架提供的实现,但如果性能不是条件,您可以简单地尝试 Transparent/RealProxy 由 remoting API.
使用
https://msdn.microsoft.com/fr-fr/library/system.runtime.remoting.proxies.realproxy(v=vs.110).aspx
这是一个老问题,但我认为贡献会很有趣,因为没有提到 DynamicProxy。
您还可以使用 DynamicProxy nuget package from Castle.Core.
您可以拦截对 class 的所有虚拟属性的 Get 和 Set 方法的调用。
I have written a Gist explaining the concept,跟踪
当访问和设置属性时。
这是拦截器的样子。
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);
}
}
我正在寻找一种在访问 属性s getter 和 setter 时自动检查访问权限的好方法。
这只是出于好奇和实验目的,所以性能并不重要。
我发现的一种方法如下(示例仅适用于 getters):
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();
}
}
}
如果未提供安全条件,则使用动态对象中止。 这种方法的问题是 class 上实际存在的属性不会由 TryGetMember 方法处理。 所以这种方法迫使我只处理代码中实际不存在的属性。
如您所见,动态功能与我的方法并不相关。 我想要一些类似的东西来处理我用代码编写的属性,不需要支持动态功能。
那么,是否有另一种方法可以在 c# 中使用,而不在每个 属性 上应用属性或向 getter 和 setter 添加自定义代码?
您可以使用代理模式。 它存在很多由 AOP 框架提供的实现,但如果性能不是条件,您可以简单地尝试 Transparent/RealProxy 由 remoting API.
使用https://msdn.microsoft.com/fr-fr/library/system.runtime.remoting.proxies.realproxy(v=vs.110).aspx
这是一个老问题,但我认为贡献会很有趣,因为没有提到 DynamicProxy。 您还可以使用 DynamicProxy nuget package from Castle.Core.
您可以拦截对 class 的所有虚拟属性的 Get 和 Set 方法的调用。
I have written a Gist explaining the concept,跟踪 当访问和设置属性时。
这是拦截器的样子。
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);
}
}