简体   繁体   中英

How to replace an instance of a base class with a derived one during runtime

I have a simple Error base class that has for the purposes of this question an int representing a possible error value.

I have a derived from this Error base class an ErrorMultiple class which has a List of ints so that I can hold multiple errors values.

There is an Event class that I wish to hold amongst other things an single instance of the Error base class.

So I create an instance of an Event and pass it around to many methods. One of these decides that “Oh no. We have discovered that there multiple errors to report."

How can I write code to get my Event object to discard it's Error base class instance and replace it with an instance of the ErrorMultiple class via a Event.ReplaceErrorObjWithMultipleErrorObj()

public class Error
{
    protected int ErrorNo;
}
public class ErrorMultiple : Error
{
    Protected List<int> MultipleErrorNos;
}
public class Event
{
    Error   *   errorObject;
}

Public Event()
{
    errorObject = new Error();
}

void Event.ReplaceErrorObjWithMultipleErrorObj()
{
    errorObject = new ErrorMultiple();
}

Of course the Event declaration is rubbish in true C# syntax. I don't know how to declare a reference to a replaceable object instance.

Issue #01 - Value Types and Reference Types In C++, objects are value types - structures of their components. To make a reference to the value as it lives in memory, you use a pointer. C# is not like this. In C#, objects are references by default, there are no values types as far as objects are concerned. (That was a bit of a lie to make this simpler)

That means that in C# this:

ErrorClass error = new ErrorClass();

Is the equivalent of this in C++:

ErrorClass* error = new ErrorClass();

The key difference however, is that there is no way to dereference a C# reference like you can dereference a pointer in C++.

Additionally this in C#:

error.ErrorNumber = 0;

Is equivalent to this in C++:

error->ErrorNumber = 0;

Effectively what is happening is that all the pointer magic is being concealed from the user in order to prevent pointer errors and to ensure that no pointer management interferes with the managed language's garbage collection (a system that deletes objects when they are finished with, ie they fall out of scope).

Issue #02 - Syntax In C#, the compiler is quite a bit different to the C++ one. It's more intelligent and less strict, though it lacks a few features like true defines and macros.

Firstly, classes must fully contain all their fields and methods in one block, you cannot declare the basic structure of a class and declare the definitions of things afterwards. ie, you cannot do this:

class ErrorClass { public: void PrintError(); }
void ErrorClass::PrintError() { printf("error"); }

Because the definition for the method must be inside the body of the class, like so:

class ErrorClass { public void PrintError() { Console.Write("error"); } }

You do not however have to declare the name of a function before it is used, the compiler does not necessarily read your code in the order it is written.

To sum everything up, I shall rewrite your code in proper C# form so you may see how things should look:

public class Error
{
    protected int ErrorNo;
}
public class ErrorMultiple : Error
{
    protected List<int> MultipleErrorNos = new List<int>();
}
public class Event
{
    Error errorObject = new Error();
public void MultiplyErrors()
{
    errorObject = new ErrorMultiple();
}
}

Please note that firstly, the error numbers cannot be read because they are protected, and that secondly C# has an exception-based system using the try,catch,finally and throw statements, similar to more modern C++.

Suggested reading:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM