C# - При возникновении исключения хотите сохранить исходное состояние объекта параметра при любых последних изменениях - PullRequest
0 голосов
/ 03 апреля 2020

Вызывающий метод передает объект в метод calle, где метод calle пытается изменить значения свойств полученного объекта при выполнении модификации, если происходит какое-то исключение, исключение будет вызвано вызывающим методом, но полученный объект будет частично / частично изменен. (потому что объекты имеют ссылочный тип)

Полу / частично заполненное - это то, чего я хотел бы избежать, при возникновении исключения хотел бы установить объект, передаваемый между методом, как ноль, или он должен иметь исходное состояние без какого-либо недавних изменений состояния. Как этого добиться в c#?

Пример кода:

  class MyClass
    {
        public int MyProperty { get; set; }

        public int MyProperty2 { get; set; }

        [MyCustomAttribute]
        public int MyProperty3 { get; set; }

    }


    MyClass DoSomething1(MyClass myClass)
    {
        try
        {
            var updatedClass = new MyClass();

            updatedClass.MyProperty = 1;

            updatedClass.MyProperty2 = 2;

            MyClass fullyUpdatedClass = DoSomething2(updatedClass);

            return fullyUpdatedClass;

        }
        catch (Exception)
        {
            //2. receives partially filled myClass, even though 
            //assigned 'null' on the catch block of calle i.e., 
            //DoSomething2(), why? this behavior or I did something wrong?
            return myClass;
        }

    }

    //as per my business req., this function will updated only those properties 
    //decorated with [MyCustomAttribute]
    MyClass DoSomething2(MyClass myClass)
    {
        try
        {
            var updatedClass = new MyClass();

            //as per my business req., since MyProperty3 decorated with [MyCustomAttribute]
            //ONLY it is getting updated here.
            updatedClass.MyProperty3 = 1;

            //@Patrick Mcvay, if I do like you have suggested below 
            //changes happened on "myClass" instance via DoSomething1() will be gone 
            myClass = updatedClass;

            return myClass;

        }
        catch (Exception ex)
        {
            //1. though I am assigning null value here for targetted object,
            //calling code (i.e., catch block of DoSomething1()) not receiving null object, instead partially filled obj. WHY?
            myClass = null;
            throw ex;
        }

    }

1 Ответ

0 голосов
/ 03 апреля 2020

Я написал консольное приложение для демонстрации и поместил довольно подробные комментарии в коде. Просто скопируйте это в новое консольное приложение и запустите.

public class Program
{
    // Example of the Program Class having an instance that is being updated
    // in this case your methods would just be voids and you wouldn't have to
    // pass in an instance of MyClass
    //static MyClass myClass;

    // This is an example of a value that the program knows about (that is outside of the methods, but being updated by the methods)
    static string message;

    static void Main(string[] args)
    {
        var myClass = new MyClass();

        var updatedClass = DoSomething1(myClass);

        // Simply checking to see if updatedClass is null and changing the message accordingly
        message += updatedClass != null ? string.Format("\nProp 1: {0} \nProp 2: {1} \nProp 3: {2}", updatedClass.MyProperty, updatedClass.MyProperty2, updatedClass.MyProperty3) : "\nException occured returned null";

        Console.WriteLine(message);

        Console.ReadLine();
    }
    // Note: since you are passing in an instance of MyClass, the rest of the program
    // does not know what is happening to this instance inside the method
    // i.e. assigning null to myClass will not return null unless you specifically
    // tell it to "return myClass;" afterwards or just "return null;"
    static MyClass DoSomething1(MyClass myClass)
    {
        try
        {
            // Unless you are working with an external instance of this class you won't need to make a new MyClass instance
            // i.e. if your Program class (in a console app) has an instance that you are updating.
            // see example above
            //var updatedClass = myClass;

            myClass.MyProperty = 1;

            // Using to throw exception (Change to anything but 0 to not throw exception)
            Console.WriteLine("Enter the value for i in DoSomething1(), putting 0 will throw an exception");
            int i = int.Parse(Console.ReadLine());

            myClass.MyProperty2 = 2/i;

            myClass = DoSomething2(myClass);

            // insert breakpoint here to see what is being returned
            return myClass;

        }
        // Note: this will not catch the exception in DoSomething2() since it is already being handled in that method
        // If you want it to catch the exception from DoSomething2() you will need to put the throw; back in
        catch (Exception ex)
        {
            // Just updating the message value to tell you which method the exception was thrown in
            message += string.Format("\nException thrown in DoSomething1()\n{0}", ex.Message);
            // Just return null here
            return null;
        }

    }

    // Note: since you are passing in an instance of MyClass, the rest of the program
    // does not know what is happening to this instance inside the method
    // i.e. assigning null to myClass will not return null unless you specifically
    // tell it to "return myClass;" afterwards or just "return null;"
    //as per my business req., this function will updated only those properties 
    //decorated with [MyCustomAttribute]
    static MyClass DoSomething2(MyClass myClass)
    {
        try
        {
            // Unless you are working with an external instance of this class you won't need to make a new MyClass instance
            // i.e. if your Program class (in a console app) has an instance that you are updating.
            // see example above
            //var updatedClass = myClass;

            // Using to throw exception (Change to anything but 0 to not throw exception)
            Console.WriteLine("Enter the value for i in DoSomething2(), putting 0 will throw an exception");
            int i = int.Parse(Console.ReadLine());
            //as per my business req., since MyProperty3 decorated with [MyCustomAttribute]
            //ONLY it is getting updated here.
            myClass.MyProperty3 = 1/i;

            // return the updated MyClass object
            // insert breakpoint here to see what is being returned
            return myClass;

        }
        catch (Exception ex)
        {
            // Just updating the message value to tell you which method the exception was thrown in
            message += string.Format("Exception thrown in DoSomething2()\n{0}", ex.Message);
            // returning null will make the entire object equal to null per the current code
            // note that only the catch in DoSomething2() is being used this way
            return null;

            // Use this if you want DoSomething1() to catch the exception
            // At this point there is really no reason for the Try Catch block
            // Unless you want to actually do something instead of just throwing the exception
            // Also, if you throw the exception here, assigning null to myClass
            // is doing nothing, because you are not returning the myClass instance.
            // like i said above the rest of the program has no idea what you
            // are doing to the myClass instance inside the method
            // uncomment the line below to show where both catch blocks are being used
            //throw;
        }

    }
}


class MyClass
{
    public int MyProperty { get; set; }

    public int MyProperty2 { get; set; }

    //[MyCustomAttribute]
    public int MyProperty3 { get; set; }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...