我想不出一个更好的方法来表达这一点,所以它可能就在那里,但我不知道它的用语.我有许多用于访问不同数据存储的类,它们遵循以下模式:
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#中这种自动实现是否可行?
最佳答案 使用任何依赖注入(DI)框架.以下使用WindsorCastle.
使用nuget安装温莎城堡.
拦截器可以在您的场景中用于拦截对方法的任何请求.
可以通过实现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.