抽象函数和数据类型 - 有没有优雅的方法来做到这一点?

时间:2012-05-23 22:43:33

标签: c# generics

我有一大堆物体,都来自单亲。这些对象都知道如何判断它们是否已经被修改,但是我还需要能够看到一个对象的新实例是否已被修改,而不是内存中已有的实例(测试是否有其他人更新了数据库)正在编辑对象。)

结果是每个子类都必须包含相同的方法:

public new bool Changed()
{
    return Changed(this);
}

这真的很适合我,但我认为没有办法绕过它,因为真正的工作需要通过一个函数来完成,该函数采用与它所在类相同类型的参数 - 因此它不能是虚拟的。 (当然,我可以定义它来接受父节点并且每次都抛出它但是这使得比较函数接受树中的任何对象而不是仅接受正确的对象,并且它在每个实例中都需要保护代码,再次丑陋。)

当然这有效,但我不喜欢丑陋的代码。

更新:对于Changed函数,每个对象在加载时都会保留其状态的副本。

3 个答案:

答案 0 :(得分:3)

只要您的基类为abstract,您就可以执行以下操作:

abstract class Base
{
    public abstract bool Changed<T>(T obj) where T : Base;

    public bool Changed()
    {
        return Changed(this);
    }
}

class Subclass : Base
{
    public override bool Changed<Subclass>(Subclass obj)
    {
        // Do stuff here
    }
}

答案 1 :(得分:2)

基本结构:

public abstract class Base<T> where T : Base<T>
{
    public T Original { get; private set; }

    public abstract bool Changed(T o);

    public bool Changed()
    {
        return this.Changed(Original);
    }
}

public class DerivedA : Base<DerivedA>
{
    public override bool Changed(DerivedA o)
    {
        throw new NotImplementedException();
    }
}

public class DerivedB : Base<DerivedB>
{
    public override bool Changed(DerivedB o)
    {
        throw new NotImplementedException();
    }
}

虽然它有缺点(readiblity),但在这种情况下它可能是正确的选择,因为你的问题不是典型的Animal / Dog / Cat意义上的类型保护,而是代码共享。

要防止出现这种情况:

public class DerivedC : DerivedB
{
}
new DerivedB().Changed(new DerivedC()); // compiles

你可以封DerivedB

或者你可以继续疯狂(我不会推荐这个。绝对不会超过这个级别):

public abstract class DerivedE<T> : Base<DerivedE<T>> where T : DerivedE<T>
{
}

public class DerivedF : DerivedE<DerivedF>
{
}

public class DerivedG : DerivedE<DerivedG>
{
}

new DerivedF().Changed(new DerivedG()); // does not compile
new DerivedF().Changed(new DerivedF()); // does compile

http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx。我从那篇文章中得到了灵感。他讨论了利弊和专业人士。

编辑:清理,根据评论进行调整

答案 2 :(得分:0)

与minitech相同的答案,所以他应该得到功劳,但在这个例子中,SubclassA的Changed可以通过强制转换为完全命名的类来查看其属性。

namespace ConsoleApplication1
{

    abstract class Base 
    {     
        protected abstract bool Changed<T>(T obj) where T : Base;      
        public bool Changed()     
        {         
            return Changed(this);     
        }

        public String PropBase { get; set; }
    }  

    class SubclassA : Base 
    {
        public String PropA { get; set; }

        protected override bool Changed<SubclassA>(SubclassA obj)     
        {
            ConsoleApplication1.SubclassA myInstance = obj as ConsoleApplication1.SubclassA;
            // Now can see PropA
            myInstance.PropA = "A";
            return true;
        }


    }

    class SubclassB : Base
    {
        protected override bool Changed<SubclassB>(SubclassB obj)
        {
            // can't see prop B here 
            // obj.PropB = "B";
            return true;
        }

        public String PropB { get; set; }
    } 


    class Program
    {
        static void Main(string[] args)
        {

            SubclassB x = new SubclassB();

            x.Changed();

            Base y = new SubclassA();

            y.Changed();
        }
    }
}