c# – 自动实现装饰器方法

我想不出一个更好的方法来表达这一点,所以它可能就在那里,但我不知道它的用语.我有许多用于访问不同数据存储的类,它们遵循以下模式:

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.
点赞