C# 具有重写方法的代理类

C# 具有重写方法的代理类,c#,.net,visual-studio,.net-4.0,C#,.net,Visual Studio,.net 4.0,在.NET 4.0应用程序中,我通过接口I设置访问应用程序属性I准备: public interface ISettings { int Quota { get; } string Property2 { get; } // ... int PropertyN { get; } } // code generated by Visual Studio public sealed partial class Settings : global::Sys

在.NET 4.0应用程序中,我通过接口
I设置访问应用程序属性
I准备:

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
}

有没有一种优雅的方法可以生成这样的类,而不必显式地实现接口的所有成员,只需将它们重定向到默认实例?

您可以使用任何框架创建设置类的动态代理。 例如,使用我可以创建一个类(在您的案例设置类中)的对象,如下所示

ISettings settings = (ISettings)Intercept.NewInstance(typeof(Settings), new VirtualMethodInterceptor(), new IInterceptionBehavior[] { new OrganizationInterceptor(orgId)});
OrganizationInterceptor能够“拦截”方法调用(包括属性getter/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; }
}
公共类OrganizationInterceptor:IInterceptionBehavior
{
私有INTORGID{get;set;}
私有列表组织的配额较大;
公共组织拦截器(INTORGID)
{
OrgId=OrgId;
WillExecute=orgId>0;
}
public IEnumerable GetRequiredInterface()
{
return Type.EmptyTypes;
}
公共IMethodReturn调用(IMethodInvoke输入,GetNextInterceptionBehaviorDelegate getNext)
{
var ret=getNext()(输入,getNext);
如果(input.MethodBase.IsSpecialName&&input.MethodBase.Name==“获取配额”&&
this.orgsWithBiggerQuota.Contains(OrgId))
ret.ReturnValue=(int)ret.ReturnValue+100;
返回ret;
}
公共bool将执行{get;set;}
}
我自己还没有运行过这个程序,所以您可能需要对它进行一些调试(尤其是Invoke方法)


如果您想使用VirtualMethodInterceptor,您需要将您的财产声明为虚拟财产。还有TransparentProxyInterceptor,它不需要这个,但会创建另一个对象来调用您的对象(虚拟情况下总共2个对象,而虚拟情况下为1个对象)。

我认为这种方法没有任何好处。您有没有理由不将此逻辑移到服务/业务层?您可能会发现它很有用。@Kamyar我希望在实现此逻辑时尽量少接触现有代码。注入修改后的设置对象是最好的,因为逻辑甚至不需要知道与平常不同的东西。我喜欢这个解决方案,因为我不想在设置可能被覆盖的任何地方都出现几十个“如果”或“开关”。@AdiLester我会看一看,谢谢。哇,在我看来,这就像是瞄准苍蝇的佳能:)。但我当然会试试。非常感谢。