我想不出一个更好的方法来表达这一点所以它可能就在那里,但我不知道它的用语。我有许多用于访问不同数据存储的类,它们遵循以下模式:
interface IUserData {
User GetUser(uint id);
User ByName(string username);
}
class UserData : IUserData {
...
}
class AuthorizedUserData : IUserData {
IUserData _Data = new UserData();
public User GetUser(uint id) {
AuthorizationHelper.Instance.Authorize();
return _Data.GetUser(id);
}
public User ByName(string name) {
AuthorizationHelper.Instance.Authorize();
return _Data.ByName(name);
}
}
所以基本设置是:
鉴于这些类实现了相同的接口,并且在包装类的每个方法的开头完成了完全相同的工作,这使我认为我可以自动化这个包装过程。
我知道在JavaScript和Python中可以创建这样的装饰器。
JavaScript中的示例:
function AuthorizedUserData() {
...
}
const userDataPrototype = Object.getPrototypeOf(new UserData());
Object.getOwnPropertyNames(userDataPrototype)
.forEach(name => {
const val = userDataPrototype[name];
if (typeof val !== 'function') {
return;
}
AuthorizedUserData.prototype[name] = function(...args) {
AuthorizationHelper.Authorize();
return this._Data[name](...args);
};
});
这种自动实现是否可以在C#中使用?
答案 0 :(得分:1)
使用任何依赖注入(DI)框架。以下使用WindsorCastle
。
使用nuget
安装Windsor Castle。
拦截器可以在您的场景中用于拦截对方法的任何请求。
可以通过实现IInterceptor
来创建拦截器public class AuthorizedUserData : IInterceptor
{
public void Intercept(IInvocation invocation)
{
//Implement validation here
}
}
使用DI容器注册依赖项并注册拦截器和类
var container = new WindsorContainer();
container.Register(Castle.MicroKernel.Registration.Component.For<AuthorizedUserData>().LifestyleSingleton());
container.Register(
Castle.MicroKernel.Registration
.Classes
.FromAssemblyInThisApplication()
.BasedOn<IUserData>()
.WithServiceAllInterfaces().Configure(
x => x.Interceptors<AuthorizedUserData>()));
您的类和接口结构如下所示
public interface IUserData
{
User GetUser(uint id);
User ByName(string username);
}
public class UserData : IUserData
{
public User GetUser(uint id)
{
throw new System.NotImplementedException();
}
public User ByName(string username)
{
throw new System.NotImplementedException();
}
}
public class User
{
}
然后使用DI容器来解析您需要的实例。在这里,我们需要一个IUserData
var user = container.Resolve<IUserData>(); // Creates an instance of UserData
user.ByName("userName"); //This call will first goto `Intercept` method and you can do validation.
答案 1 :(得分:0)
您正在寻找与 AOP 相关的内容。在.Net中,您可以使用RealProxy
这个抽象类。
这是一个很简单的方法。
创建一个类并继承RealProxy
,public override IMessage Invoke(IMessage msg)
是您的编织点。
internal class DynamicProxy<T> : RealProxy
where T : MarshalByRefObject,new()
{
private T _target;
private IMethodCallMessage callMethod = null;
private IMethodReturnMessage returnMethod = null;
public DynamicProxy(T target) : base(typeof(T))
{
_target = target;
}
public override IMessage Invoke(IMessage msg)
{
callMethod = msg as IMethodCallMessage;
MethodInfo targetMethod = callMethod.MethodBase as MethodInfo;
FilterInfo Attrs = new FilterInfo(_target, targetMethod);
ExcuteingContext excuting = Excuting(Attrs.ExcuteFilters);
if (excuting.Result != null)
{
returnMethod = GetReturnMessage(excuting.Result, excuting.Args);
}
else
{
InvokeMethod(targetMethod, excuting);
ExcutedContext excuted = Excuted(Attrs.ExcuteFilters);
}
return returnMethod;
}
private void InvokeMethod(MethodInfo targetMethod, ExcuteingContext excuting)
{
object result = targetMethod.Invoke(_target, excuting.Args);
returnMethod = GetReturnMessage(result, excuting.Args);
}
private ExcutedContext Excuted(IList<IExcuteFilter> filters)
{
ExcutedContext excutedContext = new ExcutedContext(returnMethod);
foreach (var filter in filters)
{
filter.OnExcuted(excutedContext);
if (excutedContext.Result != null)
break;
}
return excutedContext;
}
private ExcuteingContext Excuting(IList<IExcuteFilter> filters)
{
ExcuteingContext excuteContext = new ExcuteingContext(callMethod);
foreach (var filter in filters)
{
filter.OnExcuting(excuteContext);
if (excuteContext.Result != null)
break;
}
return excuteContext;
}
private ReturnMessage GetReturnMessage(object result, object[] args)
{
return new ReturnMessage(result,
args,
args.Length,
callMethod.LogicalCallContext,
callMethod);
}
}
在代理类
上获取AopBaseAttribute
过滤器(编织)
/// <summary>
/// Getting filter Attribute on proxy class
/// </summary>
public class FilterInfo
{
private List<IExcuteFilter> _excuteFilters = new List<IExcuteFilter>();
public FilterInfo(MarshalByRefObject target, MethodInfo method)
{
//search for class Attribute
var classAttr = target.GetType().GetCustomAttributes(typeof(AopBaseAttribute), true);
//search for method Attribute
var methodAttr = Attribute.GetCustomAttributes(method, typeof(AopBaseAttribute), true);
var unionAttr = classAttr.Union(methodAttr);
_excuteFilters.AddRange(unionAttr.OfType<IExcuteFilter>());
}
public IList<IExcuteFilter> ExcuteFilters
{
get
{
return _excuteFilters;
}
}
}
创建界面 IExcuteFilter
让FilterInfo
获取并编织
public interface IExcuteFilter
{
void OnExcuted(ExcutedContext excuteContext);
void OnExcuting(ExcuteingContext excutingContext);
}
封装用于执行方法的上下文。
public class ExcuteingContext
{
public ExcuteingContext(IMethodCallMessage callMessage)
{
Args = callMessage.Args;
MethodName = callMessage.MethodName;
}
public object[] Args { get; set; }
public string MethodName { get; set; }
public object Result { get; set; }
}
为Excuted方法封装上下文。
public class ExcutedContext
{
public ExcutedContext(IMethodReturnMessage returnMethod)
{
Args = returnMethod.Args;
MethodName = returnMethod.MethodName;
Result = returnMethod.ReturnValue;
}
public object[] Args { get; set; }
public string MethodName { get; set; }
public object Result { get; set; }
}
/// <summary>
/// Filter AttributeBase
/// </summary>
public abstract class AopBaseAttribute : Attribute, IExcuteFilter
{
public virtual void OnExcuted(ExcutedContext context)
{
}
public virtual void OnExcuting(ExcuteingContext context)
{
}
}
/// <summary>
/// Customer Filter
/// </summary>
public class AuthorizedUserDataAttribute : AopBaseAttribute
{
public override void OnExcuting(ExcuteingContext context)
{
//Console.WriteLine("Test");
//Implement validation here
}
}
ProxyFactory
提供代理实例。
public class ProxyFactory
{
public static TInterface GetInstance<TInterface,TObj>()
where TObj : MarshalByRefObject,new()
{
TObj proxyObj = Activator.CreateInstance(typeof(TObj)) as TObj;
return (TInterface)new DynamicProxy<TObj>(proxyObj).GetTransparentProxy();
}
}
如果您想使用需要拨打ProxyFactory.GetInstance<IUserData, UserData>
UserData
必须继承MarshalByRefObject
才能成为透明代理。
public interface IUserData
{
User GetUser(uint id);
User ByName(string username);
}
public class User
{
public string name { get; set; }
}
[AuthorizedUserData]
public class UserData : MarshalByRefObject,IUserData
{
public User GetUser(uint id)
{
return new User() { };
}
public User ByName(string username)
{
return new User() { };
}
}
IUserData user = ProxyFactory.GetInstance<IUserData, UserData>();
user.ByName("1");