运行时属性覆盖以获取历史数据

时间:2012-11-15 12:01:15

标签: c# .net reflection

我目前正在完成有关对象更改日志功能的工作,并希望对一些内容进行润色。由于我们有很多网页表格/报告应该出现历史数据,我想知道是否有办法在不改变控制/报告的情况下实施。 目前,我有这种情况:

public class Foo {
    public string Property1 { get; set; }
    public DateTime CreatedDate { get; set;}

    public string GetHistoricalValue(string propertyName) 
    {
        HistoryHelper historyHelper = CreateHistoryHelper(this);
        return historyHelper.GetHistoricalValue(propertyName, CreatedDate);
    }
...

public class HistoryHelper {
    public string GetHistoricalValue(string propertyName, DateTime date) {
    ...

因此,当有人想要获取Property1的历史数据时:

string historicalValue = fooInstance.GetHistoricalValue("Property1");

很明显,这种方法需要对当前应用程序进行大量更改。 当我以常规方式访问Property1时,有没有办法让Foo类返回历史值:

string historicalValue = fooInstance.Property1;

像动态生成具有覆盖属性的子类或其他解决方案的东西? 这可能吗?

2 个答案:

答案 0 :(得分:1)

初步答案

这样的事情:

public class Foo {
    public bool HistoricalMode { get; set; }

    private string _property1;
    public string Property1 { 
        get { 
            if (HistoricalMode) {
                return GetHistoricalValue("Property1");
            } else {
                return _property1;
            }
        set {
            if (HistoricalMode){
                throw new NotSupportedException("Updates not possible in historical mode.");
            } else {
                _property1 = value;
            }
        }
    }
    public DateTime CreatedDate { 
        get {
            // Similar pattern as above
        }
        set {
            // Similar pattern as above
        }
    }

    public string GetHistoricalValue(string propertyName) {
        HistoryHelper historyHelper = CreateHistoryHelper(this);
        return historyHelper.GetHistoricalValue(propertyName, CreatedDate);
    }
}

基本上,我们的想法是在对象中保留一个布尔值,表示对象处于“历史模式”。如果是这样,请使用您的帮助方法。如果不是,则适用普通属性getter / setter。

更新

我认为这个问题的解决方案需要对框架进行更改(如果您的所有应用程序都有一个框架)。我会按照你加载对象的方式寻求解决方案。希望您可以在“历史模式”和“正常模式”下检测何时需要对象。现在,您只需从数据库中读取对象(记录),在历史模式下,您需要从更改日志功能中组合原始对象(从发生更改时开始)。这样,您当前的所有应用程序都可以(希望)保持原样。您需要做的“唯一”更改是在存储库类中。

这只是推测btw。

答案 1 :(得分:0)

您可以轻松地影响Foo个实例的创建方式吗?如果是这样,您可以创建派生class HistoricalFoo : Foo,使Property1虚拟并使用其getter来更改其行为。然后在需要历史数据时使用HistoricalFoo。它不是一个非常干净的对象模型,但可以完成工作。

public class Foo
{
    protected string _property1;
    public virtual string Property1
    {
        get { return _property1; }
        set { _property1 = value; }
    }

    public DateTime CreatedDate { get; set;}

    /* ... */
}

public class HistoricalFoo : Foo
{
    public override string Property1
    {
        get
        {
            return GetHistoricalValue("Property1");
        }
    }
}

如果这不适用,可以在Property1 getter中嵌入一些决策逻辑。在这种情况下,您必须更改Foo实例的内部状态 - 例如,通过设置布尔标志IsInHistoryMode。但是,更改对象状态可能非常棘手,特别是在多线程环境中。

public class Foo
{
    public bool IsInHistoryMode { get; set; }

    protected string _property1;
    public virtual string Property1
    {
        get
        {
            if(IsInHistoryMode)
            {
                return GetHistoricalValue("Property1");
            }

            return _property1;
        }
        set
        {
            _property1 = value;
        }
    }

    public DateTime CreatedDate { get; set;}

    /* ... */
}