Initialize base class in .NET

2019-04-06 09:51发布

问题:

How do I go about if I need to initialize an object's base with existing object? For example, in this scenario:

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() method can, obviously assign values to the base class field-by-field, but isn't there a better solution? Since class B inherits from A, there must be a way to just assign A to the B.base

In C++ this would be a trivial thing to do, but I can't seem to grasp how to do this in .NET

回答1:

Unfortunately base is readonly.

[Edit]
Well perhaps not so unfortunate. The relationship between a base class and a child class is IS-A not HAS-A. By allowing a child class to change the instance of the base class you are allowing the child class to change its own reference since it IS-A base class. If you truly need this functionality then I would suggest you change your inheritance model to reflect what you truly want to do.

Something like this:

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

seems more appropriate and has clearer meaning and functionality.



回答2:

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

Basically, it uses reflection to get all the properties of the base and assign the values of this, to all the values that exist in A.

EDIT: To all you naysayers out there, I quickly tested this now with a base class that had 100 integer variables. I then had this assign method in a subclass. It took 46 milliseconds to run. I don't know about you, but I'm totally fine with that.



回答3:

While there are many excellent answers here, I think the proper way to do this is by chaining the constructors:

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


回答4:

No the syntax you are trying is not possible in C# .NET you need to do.

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


回答5:

Is the intent that these fields will be initialized once during object construction, or could "Assign" be called multiple times during an object's lifetime? If the latter, you can disregard the rest of this :)

Andrew's distinction between IS-A and HAS-A is an important one; if the relationship really is a HAS-A, his composition solution is the way to go.

If an IS-A relationship makes more sense (and you are able to modify A), a copy constructor might be a good idea:

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)
    {
    }
}

You end up having to copy each of A's properties, but the responsibility for doing so resides in A where it belongs.



回答6:

Why would you need to? By declaring a new B, the CLR automatically calls the constructors for both classes.

B myB = new B();

B new has the fields of both classes. However, you should declare them with an initializer unless you like nulls:

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


回答7:

I hope I'm not the only one who thinks swapping out your base class is a bad design pattern. Another approach is to replace inheritance with composition:

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

Now its trivial to write something like this:

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

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


回答8:

Wrong question. You're obviously abusing inheritance here. Try to refactor it, so that you keep a reference to A as a member field. If you need polymorphism, consider having common base class or better yet - an interface.



回答9:

According to MSDN, "base" can inly be used for the following operations:

  • Call a method on the base class that has been overridden by another method.
  • Specify which base-class constructor should be called when creating instances of the derived class.


回答10:

    [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();
            }
        }
    }


标签: c# .net oop