在.NET中初始化基类

时间:2009-01-29 18:41:13

标签: c# .net oop

如果我需要使用现有对象初始化对象的基础,我该怎么办?例如,在这种情况下:

public class A
{
    public string field1;
    public string field2;
}

public class B : A
{
    public string field3;
    public void Assign(A source)
    {
        this.base = source; // <-- will not work, what can I do here?
    }
}

Assign()方法显然可以逐字段地为基类赋值,但是没有更好的解决方案吗?由于B类继承自A,因此必须有一种方法可以将A分配给B.base

在C ++中,这将是一件微不足道的事情,但我似乎无法掌握如何在.NET中执行此操作

10 个答案:

答案 0 :(得分:18)

不幸的是,base是只读的。

[编辑]
好吧也许不那么不幸。基类和子类之间的关系是IS-A而不是HAS-A。通过允许子类更改基类的实例,您允许子类更改自己的引用,因为它是IS-A基类。如果您确实需要此功能,那么我建议您更改继承模型以反映您真正想要做的事情。

这样的事情:

public class A
{
    public string field1;
    public string field2;
}

public class B
{
    public string field3;
    public A a;

    public void Assign(A source)
    {
        this.a = source;
    }
}

似乎更合适,具有更清晰的意义和功能。

答案 1 :(得分:10)

        public Assign(A a)
        {
            foreach (var prop in typeof(A).GetProperties())
            {
                this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(a, null),null);
            }
        }

基本上,它使用反射来获取基础的所有属性,并将其值分配给A中存在的所有值。

编辑:对于你们所有的反对者,我现在用一个有100个整数变量的基类来快速测试它。然后我在子类中使用了这个assign方法。运行需要46毫秒。我不了解你,但我完全没问题。

答案 2 :(得分:5)

虽然这里有很多优秀的答案,但我认为正确的方法是链接构造函数:

public class A
{
    public string field1;
    public string field2;

    public A(string field1, string2 field2)
    {
         this.field1 = field1;
         this.field2 = field2;
    }
}

public class B : A
{
    public string field3;

    public B(string field1, string2 field2, string field3)
        : base(field1, field2)
    {
        this.field3 = field3;
    }
}

答案 3 :(得分:4)

您无需在C#.NET中尝试使用您正在尝试的语法。

public void Assign(A source) {
    field1 = source.field1;
    field2 = source.field2; 
}

答案 4 :(得分:3)

这些字段是否会在对象构建期间初始化一次,或者在对象的生命周期内可以多次调用“Assign”?如果是后者,你可以忽略其余部分:)

安德鲁对IS-A和HAS-A的区分很重要;如果这种关系真的是一个HAS-A,他的构图解决方案就是你要走的路。

如果IS-A关系更有意义(并且您能够修改A),那么复制构造函数可能是个好主意:

public class A
{
    public string field1;
    public string field2;

    public A(A copyFrom)
    {
        this.field1 = copyFrom.field1;
        this.field2 = copyFrom.field2;
    }
}

public class B : A
{
    public string field3;

    public B(A source)
        : base(source)
    {
    }
}

您最终必须复制A的每个属性,但这样做的责任在于它所属的A。

答案 5 :(得分:1)

你为什么需要?通过声明一个新的B,CLR自动调用两个类的构造函数。

B myB = new B();

B new包含两个类的字段。但是,您应该使用初始化程序声明它们,除非您喜欢null:

public string field1 = "";
public string field2 = string.Empty;

答案 6 :(得分:1)

我希望我不是唯一一个认为交换你的基类是一个糟糕的设计模式的人。另一种方法是用组合替换继承:

public class A
{
    public string Field1 { get; set; }
    public string Field2 { get; set; }
}

public class B
{
    public A A { get; set; }
    public string Field3 { get; set; }

    public B(A a) { this.A = a; }
}

现在写这样的东西是微不足道的:

B b = new B ( new A { Field1 = "hello", Field2 = "world" } );

b.A = new A { Field1 = "hola", Field2 = "luna" };

答案 7 :(得分:1)

错误的问题。 你在这里显然滥用继承权。 尝试重构它,以便您将A的引用保留为成员字段。 如果您需要多态性,请考虑使用公共基类或更好 - 接口。

答案 8 :(得分:0)

根据MSDN,“base”可以用于以下操作:

  • 在已被另一个方法覆盖的基类上调用方法。
  • 指定在创建派生类的实例时应调用哪个基类构造函数。

答案 9 :(得分:0)

    [TestMethod]
    public void TestMethod()
    {
        A a = new A();
        a.field1 = "test";
        string xml = Serialize(a);
        xml = xml.Replace("A", "B");
        B b = Deserialize(xml);

        Assert.AreEqual("test", b.field1);
    }

    public string Serialize(A a)
    {
        System.IO.StreamReader streamReader = null;
        System.IO.MemoryStream memoryStream = null;
        try
        {
            memoryStream = new System.IO.MemoryStream();
            XmlSerializer serializer = new XmlSerializer(typeof(A));
            serializer.Serialize(memoryStream, a);
            memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
            streamReader = new System.IO.StreamReader(memoryStream);
            return streamReader.ReadToEnd();
        }
        finally
        {
            if ((streamReader != null))
            {
                streamReader.Dispose();
            }
            if ((memoryStream != null))
            {
                memoryStream.Dispose();
            }
        }
    }

    public static B Deserialize(string xml)
    {
        System.IO.StringReader stringReader = null;
        try
        {
            stringReader = new System.IO.StringReader(xml);
            XmlSerializer serializer = new XmlSerializer(typeof(B));
            return ((B)(serializer.Deserialize(System.Xml.XmlReader.Create(stringReader))));
        }
        finally
        {
            if ((stringReader != null))
            {
                stringReader.Dispose();
            }
        }
    }