Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 抽象函数和数据类型——有什么优雅的方法可以做到这一点吗?_C#_Generics - Fatal编程技术网

C# 抽象函数和数据类型——有什么优雅的方法可以做到这一点吗?

C# 抽象函数和数据类型——有什么优雅的方法可以做到这一点吗?,c#,generics,C#,Generics,我有一个很大的对象家族,都是单亲的后代。这些对象都知道如何判断它们是否已被修改,但我还需要能够查看与内存中已有的实例相比,对象的新实例是否已被修改(测试是否有其他人在编辑对象时更新了数据库) 结果是每个子类必须包含相同的方法: public new bool Changed() { return Changed(this); } 这确实是我的难题,但我认为没有办法解决它,因为真正的工作需要由一个函数来完成,该函数采用与它所在的类相同类型的参数,因此它不能是虚拟的。(当然,我可以将其定义

我有一个很大的对象家族,都是单亲的后代。这些对象都知道如何判断它们是否已被修改,但我还需要能够查看与内存中已有的实例相比,对象的新实例是否已被修改(测试是否有其他人在编辑对象时更新了数据库)

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

public new bool Changed()
{
    return Changed(this);
}
这确实是我的难题,但我认为没有办法解决它,因为真正的工作需要由一个函数来完成,该函数采用与它所在的类相同类型的参数,因此它不能是虚拟的。(当然,我可以将其定义为每次接受父对象并强制转换它,但这会使比较函数接受树中的任何对象,而不仅仅是正确的对象,而且在每个实例中都需要保护代码,这也是一件难看的事情。)

这当然有效,但我不喜欢难看的代码


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

只要您的基类是
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
    }
}
抽象类基类
{
公共抽象bool-Changed(T-obj),其中T:Base;
公共布尔值已更改()
{
退货变更(本次);
}
}
类子类:Base
{
公共覆盖布尔值已更改(子类obj)
{
//在这里做事
}
}
基本结构:

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();
    }
}
您可以密封
DerivedB

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

公共抽象类DerivedE:Base,其中T:DerivedE
{
}
公共类DerivedF:DerivedE
{
}
公开课嘲笑:嘲笑
{
}
新建DerivedF()。已更改(新建DerivedG());//不编译
新建DerivedF()。已更改(新建DerivedF());//编译
看这个。我从那篇文章中得到了灵感。他讨论利弊


编辑:清理,根据注释进行调整

与minitech的答案相同,因此他应该获得学分,但在本例中,子类的更改可以通过强制转换到完全命名的类来查看其属性

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();
        }
    }
}
命名空间控制台应用程序1
{
抽象类基
{     
受保护的抽象bool-Changed(T-obj),其中T:Base;
公共布尔值已更改()
{         
退货变更(本次);
}
公共字符串PropBase{get;set;}
}  
类subassa:Base
{
公共字符串PropA{get;set;}
受保护的覆盖布尔值已更改(子类obj)
{
ConsoleApplication1.subassa myInstance=obj作为ConsoleApplication1.subassa;
//现在我可以看到普罗帕了
myInstance.PropA=“A”;
返回true;
}
}
类B子类:基
{
受保护覆盖布尔值已更改(子类B obj)
{
//这里看不到道具B
//obj.PropB=“B”;
返回true;
}
公共字符串PropB{get;set;}
} 
班级计划
{
静态void Main(字符串[]参数)
{
子类B x=新的子类B();
x、 改变();
基y=新的子类();
y、 改变();
}
}
}

它看起来像我想要的——但它无法编译。我不确定发生了什么,但参数只包含父类的字段,而不包含我需要查看的当前类的字段。我唯一可以更改的是将T更改为受保护的。我想您应该总是在类的外部调用基Changed。我只是尝试了一个测试用例,得到了相同的结果。由于对从Base派生的泛型to类的约束,该方法只能看到Base的成员。找到了解决方法。您可以将obj参数强制转换为该类型的完全限定名,并获得对属性的访问:MyNamespace.Subclass refObj=obj as MyNamespace.Subclass。你可以通过refObj获得所有道具。如果您不使用完整的名称空间,它似乎仍然认为它是T参数,您可以详细说明您的
Changed()
,分享一些具体的例子。我可以根据
Changed(SomeDerivedType o)
在每个派生类中实现的情况来调整我的示例?写几行关于基类和派生类的示例确实会有所帮助:-)我就到此为止now@skarmats:每个派生类实现的更改是正确的(另一个不编译的答案是:它抱怨类型不是泛型的,不能用作类型参数。我的基本示例是编译的。请分享更多关于您的代码的信息,我很乐意进行研究。请参阅我对OPI的评论,我没有说派生类没有被继承,其中一些是。总之,错误是“非泛型类型不能与类型参数一起使用",它被放在类行上。您确实需要将我上面展示的原则应用到您自己的类中。如果您不将基类声明为泛型,这将无法工作。我邀请您使用我的基本示例来体验解决方案。我在这里真的很困惑--即使使用cast,它仍然看不到它!您标记的是.Net的哪个版本eting?这在.Net 4.0中适用。测试用例适用于.Net 3.5和.Net 4.0。请注意,我确实安装了适用于.Net 4.0和VS2010的SP1。
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
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();
        }
    }
}