【问题标题】:Proxy class with overriden methods具有重写方法的代理类
【发布时间】:2013-10-04 09:49:15
【问题描述】:

在我的 .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
}

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

【问题讨论】:

  • 我认为这种方法没有任何好处。您是否有任何理由不将此逻辑移至您的服务/业务层?
  • 您可能会发现T4 code generation 很有用。
  • @Kamyar 我想以最少的接触现有代码的需要来实现逻辑。注入修改后的设置对象是 IMO 最好的方法,因为逻辑甚至不需要知道某些东西与平常不同。我喜欢这个解决方案,因为我不想在设置可能被覆盖的任何地方都有几十个“ifs”或“switches”。
  • @AdiLester 我去看看,谢谢。

标签: c# .net visual-studio .net-4.0


【解决方案1】:

您可以使用任何现有的框架来创建 Settings 类的动态代理。 例如使用Unity 我可以像这样创建一个类的对象(在你的情况下是设置类)

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; }
}

我自己没有运行过这个,所以你可能需要调试一下(尤其是 Invoke 方法)。

如果您想使用 VirtualMethodInterceptor,您需要将您的属性声明为虚拟。还有一个透明代理拦截器,它不需要这个,但会创建另一个对象来调用你的对象(总共 2 个对象与虚拟案例中的 1 个)。

【讨论】:

  • 哇,这在我看来就像瞄准苍蝇的佳能:)。但我当然会尝试。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-19
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多