具有重写方法的代理类
本文关键字:代理 方法 重写 | 更新日期: 2023-09-27 18:33:48
在我的 .NET 4.0 应用程序中,我正在通过我准备ISettings
接口访问应用程序属性:
public interface ISettings
{
int Quota { get; }
string Property2 { get; }
// ...
int PropertyN { get; }
}
// code generated by Visual Studio
public sealed partial class Settings :
global::System.Configuration.ApplicationSettingsBase
{
// application properties generated from app.config
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("123")]
public int Quota {
get {
return ((int)(this["Quota"]));
}
}
// and so on...
}
// my code to apply the interface to the Settings class
public sealed partial class Settings : ISettings
{
}
在某些情况下,我想根据我正在为其处理数据的组织覆盖配置文件中的值,例如,我想增加某个组织的配额。当然,我可以创建类似于以下内容的方法:
public int GetQuotaByOrgId(int orgId);
并在那里实现逻辑,但我想避免在代码之间传递orgId
。对我来说,更好的解决方案是创建一个代理类,仅覆盖我想要更改的值,如下所示:
public class OverridenSettings : ISettings
{
private ISettings instance;
private int orgId;
private int[] orgsWithBiggerQuota = {1, 2, 132, 6542};
public OverridenSettings(ISettings instance, int orgId)
{
this.instance = instance;
this.orgId = orgId;
}
public override int Quota
{
get
{
int quota = this.instance.Quota;
if (this.orgsWithBiggerQuota.Contains(this.orgId))
{
quota += 1000;
}
return quota;
}
}
// all other properties should be taken from the default instance
}
有没有一种优雅的方法来生成这样的类,而不必显式实现接口的所有成员只是为了将它们重定向到默认实例?
您可以使用任何框架来创建 Settings 类的动态代理。例如,使用 Unity 我可以像这样创建一个类的对象(在您的例子中是 Settings 类)
ISettings settings = (ISettings)Intercept.NewInstance(typeof(Settings), new VirtualMethodInterceptor(), new IInterceptionBehavior[] { new OrganizationInterceptor(orgId)});
OrganizationInterceptor 能够"拦截"方法调用(包括属性获取者/setter),并且可以具有如下实现:
public class OrganizationInterceptor : IInterceptionBehavior
{
private int OrgId { get; set; }
private List<int> orgsWithBiggerQuota;
public OrganizationInterceptor(int orgId)
{
OrgId = orgId;
WillExecute = orgId > 0;
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var ret = getNext()(input, getNext);
if (input.MethodBase.IsSpecialName && input.MethodBase.Name == "get_Quota" &&
this.orgsWithBiggerQuota.Contains(OrgId))
ret.ReturnValue = (int)ret.ReturnValue + 100;
return ret;
}
public bool WillExecute { get; set; }
}
我自己还没有运行过这个,所以你可能需要稍微调试一下(尤其是 Invoke 方法)。
如果要使用 VirtualMethodInterceptor,则需要声明属性 virtual。还有 TransparentProxyInterceptor,它不需要这个,但会创建另一个对象来调用你的对象(总共 2 个对象,虚拟情况下为 1 个)。