none
Can someone draw a UML Diagram for this code example? RRS feed

  • Question

  • Hi there. I have a problem to understand the flux of the program. I put some Writelines inside get and set etc, and the revelations made things really worst. For example, as you may see in the photo, GrossSales\set\if and CommissionRate\set\if appear first, where FirstName, LastName and SocialSecurityNumber "should' appear first. Further more, lines 7-8 are repeated in lines 9 and 10. Why twice? The same happens 26-27 and 28-29. Can someone draw any flux diagram?

    (See Console Output below

    ---------------------------------------------------------------------------------------------------------------------------

    Advertise Employee 's data and earnings:
    Commission rate: Sue Jones
    Social Security Number: 222-22-2222
    Gross sales: $10000.00
    Commission rate: 0.06
    Earnings: 600.00

    Updating employee' s data:
    New gross sales: 12000
    new commission rate: 0.068
    Inside GrossSales\set\if
    Inside CommissionRate\set\if
    Inside FirstName\get
    Inside LastName\get
    Inside SocialSecurityNumber\get
    Inside GrossSales\get
    Inside CommissionRate\get
    Inside GrossSales\get
    Inside CommissionRate\get
    Advertise Employee 's data and earnings:
    Commission rate: Sue Jones
    Social Security Number: 222-22-2222
    Gross sales: $12000.00
    Commission rate: 0.07
    Earnings: 816.00

    ----------------------------------------------------------------------------------------------------------------------

    using System;
    public class CommissionEmployee : Object
    {
        private string fN, lN, sSN;
        private decimal grossSales = 0, commissionRate = 0;
        public string FirstName
        {        
            get { Console.WriteLine("Inside FirstName\\get"); return fN; }
        }
        public string LastName
        {
            get { Console.WriteLine("Inside LastName\\get"); return lN; }
        }
        public string SocialSecurityNumber
        {
            get { Console.WriteLine("Inside SocialSecurityNumber\\get"); return sSN; }
        }
        public decimal GrossSales
        {
            get { Console.WriteLine("Inside GrossSales\\get"); return grossSales; }
            set
            {
                if (value >= 0)
                {
                    Console.WriteLine("Inside GrossSales\\set\\if"); 
                    grossSales = value;
                }                
                else
                {
                    Console.WriteLine("Inside GrossSales\\set\\else");
                    throw new ArgumentOutOfRangeException("Gross Sales", value, "Gross Sales must be a non negative");
                }                
            }
        }
        public decimal CommissionRate
        {
            get { Console.WriteLine("Inside CommissionRate\\get"); return commissionRate; }       
            set
            {
                if (value >= 0 && value <= 1)
                {
                    Console.WriteLine("Inside CommissionRate\\set\\if");
                    commissionRate = value;
                }                
                else
                {
                    Console.WriteLine("Inside CommissionRate\\set\\else");
                    throw new ArgumentOutOfRangeException("Commission Rate", value, "invalid Commission Rate value");
                }                
            }
        }
        public CommissionEmployee(string f, string l, string ssn, decimal gSales, decimal cRate)
        {
            fN = f;
            lN = l;
            sSN = ssn;
            GrossSales = gSales;
            CommissionRate = cRate;
        }
        public string StringFormat()
        {
            return string.Format("{0}: {1} {2}\n{3}: {4}\n{5}: ${6}\n{7}: {8:F2}\nEarnings: {9:F2}",
                "Commission rate", FirstName, LastName, "Social Security Number", SocialSecurityNumber,
                "Gross sales", GrossSales, "Commission rate", CommissionRate, commisionRateEarning());
        }
        private decimal commisionRateEarning()
        {
            return GrossSales * CommissionRate;
        }
    }
    using System;
    public class Program
    {
        public static void Main(string[] args)
        {
            CommissionEmployee emp1 = new CommissionEmployee("Sue", "Jones", "222-22-2222", 10000.00M, .06M);
            Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", emp1.StringFormat());
            Console.WriteLine();
            Console.WriteLine("Updating employee' s data:\nNew gross sales: 12000\nnew commission rate: 0.068\n");
            emp1.GrossSales = 12000.00M;
            emp1.CommissionRate = 0.068M;
            Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", emp1.StringFormat());
      
            Console.ReadKey();
        }
    }
    
    
    

    Thanx!

    Saturday, August 11, 2018 11:50 AM

Answers

  • No UML needed. 

    The explanation is simple: The first action is to create (instantiate) the object. The first method called is always the constructor. In the constructor, you set first name, last name, SSN, gross sales and commision rate by accessing the backing fields directly. Thus the accessors (getter and setter) are not used, so no output for these five values.

    Then you change two values, thus the corresponding two setter outputs.

    After this, you use CommissionEmployee.StringFormat() method (hint: look up how to override ToString() instead).

    In the StringFormat() method, you use gross sales and CommisionRate. These result in the first output of their getters. But you also call CommissionEmployee.commisionRateEarning(). Which calls internally those two again by their getters.

    To change this behavior, you may consider changing the CommissionEmployee.commisionRateEarning() method to:

    private decimal commisionRateEarning()
    {
        return grossSales * commissionRate;
    }

    p.s. use the toolbar icon with <> to embed code into your posts. 

    UPDATE:

    Sorry for the typos.

    In the StringFormat() method, you use gross sales and CommisionRate. These result in the first output of their getters. But you also call CommissionEmployee.commisionRateEarning(). Which calls internally those two again by their getters.

    I meant:

    In the StringFormat() method, you use GrossSales and CommisionRate. These result in the first output of their getters. But you also call CommissionEmployee.commisionRateEarning(). Which calls internally those two again by their getters.


    Saturday, August 11, 2018 10:55 PM
  • There are two patterns for the using clause in relation to the project's namespace:

    1. Placing it in the outer scope:

    using libraryNamspace;
    
    namespace actualProjectNamespace
    {
    }

    and

    2. placing it in the inner scope

    namespace actualProjectNamespace
    {
        using libraryNamspace;
    }

    And it's imho obvious, that the above code contains at least two files. Thus the OP's using the first (default) way.

    I did not confuse backing field with property, it was indeed a typo and auto-correction.

    p.s. indeed, I'm not a native speaker, so you should have taken that into account. btw, it's the second/third abbreviation.


    Sunday, August 12, 2018 11:30 AM
  • a) No. ToString() is a general method to generate string output. It is the default method called when a string is required. It means, that you don't need any longer need to specify the method explicitly.

    E.g.

    CommissionEmployee emp1 = new CommissionEmployee("Sue", "Jones", "222-22-2222", 10000.00M, .06M);
    Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", emp1);

    b) A class encapsulates date and behavior. Class level variables are called fields. Fields which are private, but are used for properties, in their getters and setters, are called backing fields. Well, they back the property.

    I refactored your code, cause using abbreviations is a code smell. See clean code and opacity. Abbreviations are harder to read and understand. They should be only used when they are absolutely common for all users in that domain. I also refactored it, cause I think using common style rules makes code easier to read in the long term (nuget StyleCop.Analyzers).

    About using properties in the constructor (ctor):

    public CommissionEmployee(string f, string l, string ssn, decimal gSales, decimal cRate)
    {
        FirstName = f;
        LastName = l;
        SocialSecurityNumber = ssn;
        GrossSales = gSales;
        CommissionRate = cRate;
    }


    The problem is - see also the other answer about using properties vs fields in internal methods: the constructor should only construct an object instance. Nothing more. It should have no side effects in the domain. The additional output of the setters is such a side-effect. Of course, this is not a general rule, cause what a side-effect is depended on the domain your code is working and the requirements.

    Please copy code only from VS after successfully compiling it. Cause this would give you already  the answer to your question:

    It says "return fN". How is fN assigned a value??? This is why I asked for a diagram

    The code in the current, assumed state would not compile. Cause there is no setter for the FirstName property.

    c) Here again, we need to distinguish between backing fields and properties. After instantiating, all fields of a class are initialized. Either explicitly in the constructor or by using explicit default values or by using the data types implicit default values. E.g. like this:

    public class CommissionEmployee
    {
    	private readonly string firstName;
    	private readonly string lastName;
    	private readonly string socialSecurityNumber;
    	private decimal grossSales = 0;
    	private decimal commissionRate = 0;
    
    	public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber)
    	{
    		Console.WriteLine("* Entering ctor (1)..");
    		this.firstName = firstName;
    		this.lastName = lastName;
    		this.socialSecurityNumber = socialSecurityNumber;
    		Console.WriteLine("* Leaving ctor (1).");
    	}
    
    	public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber, decimal grossSales, decimal commissionRate)
    	{
    		Console.WriteLine("* Entering ctor (2)..");
    		this.firstName = firstName;
    		this.lastName = lastName;
    		this.socialSecurityNumber = socialSecurityNumber;
    		this.GrossSales = grossSales;
    		this.CommissionRate = commissionRate;
    		Console.WriteLine("* Leaving ctor (2).");
    	}
    
    	// []..]
    }

    As the backing fields for gross sales and commision rate have an explicit default value, we can add a  second ctor, which uses these. So we can use a simplified instantiation:

    public class Program
    {
    	public static void Main(string[] args)
    	{
    		CommissionEmployee employee2 = new CommissionEmployee("Hank", "Jones", "333-33-33");
    		Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", employee2);
    
    		Console.WriteLine("\nDone.");
    		Console.ReadLine();
    	}
    }
    

    which gives us this result:

    As properties consist of backing fields, getter and setter methods, we can only say that a property is initialized, when its backing fields are initialized. But this is only true from the plain compiler perspective. It is not true from the domain (business) view. Cause we have the concept of lazy initialization (using Lazy<T>) and proxy objects (proxy pattern) to enhance performance. Lazy property example using classic lazy initialization considering the creation of a Dummy instance is slow: 

    namespace ConsoleCS
    {
        using System;
    
        public class Dummy
        {
        }
    
        public class CommissionEmployee
        {
            private Dummy dummy;
    
            public Dummy Dummy
            {
                get
                {
                    if (this.dummy == null)
                    {
                        this.dummy = new Dummy();
                    }
    
                    return this.dummy;
                }
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee commissionEmployee = new CommissionEmployee();
                Console.WriteLine(commissionEmployee.Dummy);
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }
    

    The complete sample for the above scenarios without the lazy sample:

    namespace ConsoleCS
    {
        using System;
    
        public class CommissionEmployee
        {
            private readonly string firstName;
            private readonly string lastName;
            private readonly string socialSecurityNumber;
            private decimal grossSales = 0;
            private decimal commissionRate = 0;
    
            public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber)
            {
                Console.WriteLine("* Entering ctor (1)..");
                this.firstName = firstName;
                this.lastName = lastName;
                this.socialSecurityNumber = socialSecurityNumber;
                Console.WriteLine("* Leaving ctor (1).");
            }
    
            public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber, decimal grossSales, decimal commissionRate)
            {
                Console.WriteLine("* Entering ctor..");
                this.firstName = firstName;
                this.lastName = lastName;
                this.socialSecurityNumber = socialSecurityNumber;
                this.GrossSales = grossSales;
                this.CommissionRate = commissionRate;
                Console.WriteLine("* Leaving ctor.");
            }
    
            public string FirstName
            {
                get
                {
                    Console.WriteLine("* Inside FirstName get.");
                    return this.firstName;
                }
            }
    
            public string LastName
            {
                get
                {
                    Console.WriteLine("* Inside LastName get.");
                    return this.lastName;
                }
            }
    
            public string SocialSecurityNumber
            {
                get
                {
                    Console.WriteLine("* Inside SocialSecurityNumber get.");
                    return this.socialSecurityNumber;
                }
            }
    
            public decimal GrossSales
            {
                get
                {
                    Console.WriteLine("* Inside GrossSales get.");
                    return this.grossSales;
                }
    
                set
                {
                    Console.WriteLine("* Inside GrossSales set.");
                    if (value >= 0)
                    {
                        this.grossSales = value;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("Gross Sales", value, "Gross Sales must be a non negative");
                    }
                }
            }
    
            public decimal CommissionRate
            {
                get
                {
                    Console.WriteLine("* Inside CommissionRate get.");
                    return this.commissionRate;
                }
    
                set
                {
                    Console.WriteLine("* Inside CommissionRate set.");
                    if (value >= 0 && value <= 1)
                    {
                        this.commissionRate = value;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("Commission Rate", value, "invalid Commission Rate value");
                    }
                }
            }
    
            public override string ToString()
            {
                Console.WriteLine("* Inside ToString().");
                return $"{"Commission rate"}: {this.firstName} {this.lastName}\n{"Social Security Number"}: {this.socialSecurityNumber}\n{"Gross sales"}: ${this.grossSales}\n{"Commission rate"}: {this.commissionRate:F2}\nEarnings: {this.CommisionRateEarning():F2}";
            }
    
            private decimal CommisionRateEarning()
            {
                Console.WriteLine("* Inside CommisionRateEarning().");
                return this.grossSales * this.commissionRate;
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee employee1 = new CommissionEmployee("Sue", "Jones", "222-22-2222", 10000.00M, .06M);
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", employee1);
                Console.WriteLine();
                Console.WriteLine("Updating employee' s data:\nNew gross sales: 12000\nnew commission rate: 0.068\n");
                employee1.GrossSales = 12000.00M;
                employee1.CommissionRate = 0.068M;
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", employee1);
    
                Console.WriteLine("\n---\n");
                CommissionEmployee employee2 = new CommissionEmployee("Hank", "Jones", "333-33-33");
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", employee2);
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    and its complete output:

    Sunday, August 12, 2018 4:12 PM
  • and the program runs as fine as previously. Then, why should one declare them?

    Just because, we don't call it in the actual sample. Someone else might. E.g.

    namespace ConsoleCS
    {
        using System;
    
        public class CommissionEmployee
        {
            private readonly string firstName;
            private readonly string lastName;
    
            public CommissionEmployee(string firstName, string lastName)
            {
                Console.WriteLine("* Entering ctor..");
                this.firstName = firstName;
                this.lastName = lastName;
                Console.WriteLine("* Leaving ctor.");
            }
    
            public string FirstName
            {
                get
                {
                    Console.WriteLine("* Inside FirstName get.");
                    return this.firstName;
                }
            }
    
            public string LastName
            {
                get
                {
                    Console.WriteLine("* Inside LastName get.");
                    return this.lastName;
                }
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee emp1 = new CommissionEmployee("Sue", "Jones");
                Console.WriteLine($"{emp1.FirstName} {emp1.LastName}");
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    with 

    This part is the design part when developing. According to the requirements, you add the necessary properties to your class.

    return $"{"Commission rate"}: {this.firstName} {this.lastName}\n{"Social Security Number"}: {this.socialSecurityNumber}\n{"Gross sales"}: ${this.grossSales}\n{"Commission rate"}: {this.commissionRate:F2}\nEarnings: {this.CommisionRateEarning():F2}";
    is called string interpolation.


    Sunday, August 12, 2018 6:18 PM
  • The value variable is automatically declared in a setter. There it is of the type of the property and it contains the new value.

    So your snippet must look like:

    public decimal GrossSales
    {        
    	get 
    	{ 
    		Console.WriteLine("* Inside GrossSales get."); 
    		return value; 
    	}
    
    	set
    	{
    		if (value >= 0)
    		{
    			Console.WriteLine("* Inside GrossSales set.");
    			this.grossSales = value;
    		}
    	}
    }

    You should not throw exceptions in normal properties. See also Property Design. 

    If you need an exception, then you should consider using a method to set the value instead of a property.

    The other approach would be by accepting the wrong value but throwing the exception in a method where you access the backing fields. E.g.

    namespace ConsoleCS
    {
        using System;
    
        public class CommissionEmployee
        {
            public CommissionEmployee(string firstName, string lastName)
            {
                Console.WriteLine("* Entering ctor..");
                this.FirstName = firstName;
                this.LastName = lastName;
                Console.WriteLine("* Leaving ctor.");
            }
    
            public decimal CommissionRate { get; set; } = 0;
    
            public string FirstName { get; }
    
            public decimal GrossSales { get; set; } = 0;
    
            public string LastName { get; }
    
            public decimal CommisionRateEarning()
            {
                Console.WriteLine("* Inside CommisionRateEarning().");
                if (this.GrossSales < 0)
                {
                    throw new ArgumentException("Gross sales must be equal or greater than 0.");
                }
    
                return this.GrossSales * this.CommissionRate;
            }
    
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee emp1 = new CommissionEmployee("Sue", "Jones");
                Console.WriteLine($"{emp1.FirstName} {emp1.LastName}");
                try
                {
                    Console.WriteLine($"{emp1.CommisionRateEarning()}");
                }
                catch (Exception exception)
                {
                    Console.WriteLine($"! {exception.Message}");
                }
    
                emp1.GrossSales = -1;
                try
                {
                    Console.WriteLine($"{emp1.CommisionRateEarning()}");
                }
                catch (Exception exception)
                {
                    Console.WriteLine($"! {exception.Message}");
                }
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    Depending on the kind of class, like Time, where you have correlated backing fields. E.g.

    namespace ConsoleCS
    {
        using System;
    
        public class Time
        {
            private int hour;
            private int minute;
            private int second;
    
            public Time(int hour, int minute, int second)
            {
                this.SetTime(hour, minute, second);
            }
    
            public void SetTime(int hour, int minute, int second)
            {
                if (!(hour >= 0 && hour < 24) ||
                    !(minute >= 0 && minute < 60) ||
                    !(second >= 0 && second < 60))
                {
                    throw new ArgumentException("Incorrect parameters.");
                }
    
                this.hour = hour;
                this.minute = minute;
                this.second = second;
            }
    
            public override string ToString()
            {
                return $"{this.hour:00}:{this.minute:00}:{this.second:00}";
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                Time time = new Time(11, 12, 13);
                try
                {
                    Console.WriteLine($"{time}");
                    time.SetTime(12, 13, 14);
                    Console.WriteLine($"{time}");
                }
                catch (Exception exception)
                {
                    Console.WriteLine($"! {exception.Message}");
                }
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    Sunday, August 12, 2018 7:16 PM

All replies

  • No UML needed. 

    The explanation is simple: The first action is to create (instantiate) the object. The first method called is always the constructor. In the constructor, you set first name, last name, SSN, gross sales and commision rate by accessing the backing fields directly. Thus the accessors (getter and setter) are not used, so no output for these five values.

    Then you change two values, thus the corresponding two setter outputs.

    After this, you use CommissionEmployee.StringFormat() method (hint: look up how to override ToString() instead).

    In the StringFormat() method, you use gross sales and CommisionRate. These result in the first output of their getters. But you also call CommissionEmployee.commisionRateEarning(). Which calls internally those two again by their getters.

    To change this behavior, you may consider changing the CommissionEmployee.commisionRateEarning() method to:

    private decimal commisionRateEarning()
    {
        return grossSales * commissionRate;
    }

    p.s. use the toolbar icon with <> to embed code into your posts. 

    UPDATE:

    Sorry for the typos.

    In the StringFormat() method, you use gross sales and CommisionRate. These result in the first output of their getters. But you also call CommissionEmployee.commisionRateEarning(). Which calls internally those two again by their getters.

    I meant:

    In the StringFormat() method, you use GrossSales and CommisionRate. These result in the first output of their getters. But you also call CommissionEmployee.commisionRateEarning(). Which calls internally those two again by their getters.


    Saturday, August 11, 2018 10:55 PM
  • Yeah, got me. But you missed the real error: Typos.

    I meant GrossSales and CommissionRate. 

    p.s. can you tell us how to use Split() correctly on CSV rows?




    Sunday, August 12, 2018 2:04 AM
  • Notice, you posted a using statement (in your code) in a wrong place.

    Scope, not order. The only point would have been: double usage.

    p.s. please, try at least TOFU.

    Sunday, August 12, 2018 2:16 AM
  • There are two patterns for the using clause in relation to the project's namespace:

    1. Placing it in the outer scope:

    using libraryNamspace;
    
    namespace actualProjectNamespace
    {
    }

    and

    2. placing it in the inner scope

    namespace actualProjectNamespace
    {
        using libraryNamspace;
    }

    And it's imho obvious, that the above code contains at least two files. Thus the OP's using the first (default) way.

    I did not confuse backing field with property, it was indeed a typo and auto-correction.

    p.s. indeed, I'm not a native speaker, so you should have taken that into account. btw, it's the second/third abbreviation.


    Sunday, August 12, 2018 11:30 AM
  • I would expect to see the set\gets in the order they appear in the Constructor's parameter. That is, FName, LName, SSN, GrossSales and finally CommissionRate. About using, it is supposed that I use a new .cs Item.
    Sunday, August 12, 2018 2:07 PM
  • Just review your output. Using a modified version of your code:

    namespace ConsoleCS
    {
        using System;
    
        public class CommissionEmployee
        {
            private readonly string firstName;
            private readonly string lastName;
            private readonly string socialSecurityNumber;
            private decimal grossSales = 0;
            private decimal commissionRate = 0;
    
            public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber, decimal grossSales, decimal commissionRate)
            {
                Console.WriteLine("* Entering ctor..");
                this.firstName = firstName;
                this.lastName = lastName;
                this.socialSecurityNumber = socialSecurityNumber;
                this.GrossSales = grossSales;
                this.CommissionRate = commissionRate;
                Console.WriteLine("* Leaving ctor.");
            }
    
            public string FirstName
            {
                get
                {
                    Console.WriteLine("* Inside FirstName get.");
                    return this.firstName;
                }
            }
    
            public string LastName
            {
                get
                {
                    Console.WriteLine("* Inside LastName get.");
                    return this.lastName;
                }
            }
    
            public string SocialSecurityNumber
            {
                get
                {
                    Console.WriteLine("* Inside SocialSecurityNumber get.");
                    return this.socialSecurityNumber;
                }
            }
    
            public decimal GrossSales
            {
                get
                {
                    Console.WriteLine("* Inside GrossSales get.");
                    return this.grossSales;
                }
    
                set
                {
                    Console.WriteLine("* Inside GrossSales set.");
                    if (value >= 0)
                    {
                        this.grossSales = value;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("Gross Sales", value, "Gross Sales must be a non negative");
                    }
                }
            }
    
            public decimal CommissionRate
            {
                get
                {
                    Console.WriteLine("* Inside CommissionRate get.");
                    return this.commissionRate;
                }
    
                set
                {
                    Console.WriteLine("* Inside CommissionRate set.");
                    if (value >= 0 && value <= 1)
                    {
                        this.commissionRate = value;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("Commission Rate", value, "invalid Commission Rate value");
                    }
                }
            }
    
            public string StringFormat()
            {
                return $"{"Commission rate"}: {this.FirstName} {this.LastName}\n{"Social Security Number"}: {this.SocialSecurityNumber}\n{"Gross sales"}: ${this.GrossSales}\n{"Commission rate"}: {this.CommissionRate:F2}\nEarnings: {this.CommisionRateEarning():F2}";
            }
    
            private decimal CommisionRateEarning()
            {
                Console.WriteLine("* Inside CommisionRateEarning() get.");
                return this.GrossSales * this.CommissionRate;
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee emp1 = new CommissionEmployee("Sue", "Jones", "222-22-2222", 10000.00M, .06M);
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", emp1.StringFormat());
                Console.WriteLine();
                Console.WriteLine("Updating employee' s data:\nNew gross sales: 12000\nnew commission rate: 0.068\n");
                emp1.GrossSales = 12000.00M;
                emp1.CommissionRate = 0.068M;
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", emp1.StringFormat());
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }
    

    results in

    p.s. please edit your original post and embed the code and text output using the <> button in the toolbar.

    Sunday, August 12, 2018 2:28 PM
  • a) Let us start from ToString() overriding. ToString() appears to be inherited (from somewhere, like class Object or a Systemic class, no matter here where) by CommissionEmployee. This is a method that lies somewhere in the System as a virtual method, I think. Then, in the CommissionEmployee, it goes overridden. If there were a derived class, example BasePlusCommissioEmployee : CommissionEmployee, ToString() can be ulterior overridden. It can be overridden again, I hope. So, I wanted to see the behavior of a virtual method and that is because I created virtual StringFormat(). You see, in the revision of the C# manual, I would see in the base class the keyword 'override' instead of 'virtual' and initially it caused me confusion. It is not a big deal to use virtual StringFormat(), it seems that it works.

    ) I didn't know what a backing field is, but I think I get it now. Now, if you type in the Constructor { fN = f; }, fN gets the value f and holds it in memory. Then, StringFormat() calls FirstName, then the 'get'  procedure starts, and finally fN (which is already assigned the value f, as said) is returned. It sounds reasonable as a flux. On the contrary, and if I have understood well, people here ask me to modify the Constructor as that:

    public CommissionEmployee(string f, string l, string ssn, decimal gSales, decimal cRate)
        {
            FirstName = f;
            LastName = l;
            SocialSecurityNumber = ssn;
            GrossSales = gSales;
            CommissionRate = cRate;
        }

    But look at this:

    public string FirstName
        {       
            get { Console.WriteLine("Inside FirstName\\get"); return fN; }
        }

    It says "return fN". How is fN assigned a value??? This is why I asked for a diagram. 

    c) Ooooooohhhhh, great, you are right!!! So, I am -in a way- mistaking here 

    private decimal commisionRateEarning()
        {
            return GrossSales * CommissionRate;

       }

    But shouldn't there the initialization of GrossSales and CommissionRate happen only once (in this case  inside StringFormat()) and that is all? Do GrossSales and CommissionRate (and also FirstName, LastName and SocialSecurityNumber) initialize themselves each time they are called/used somewhere in the program? If so, does it worth to use {set; get;} style or should there a simple C/C++ style applied? It just does not seem alright. I mean, I think so, not sure! Thank you.

    Sunday, August 12, 2018 2:37 PM
  • Typing so

    public string FirstName
        {       
            get { Console.WriteLine("Inside FirstName\\get"); return fN; }
        }

    is not any divine inspiration of mine. It is the instructions from the C# book.

    Sunday, August 12, 2018 2:40 PM
  • Well man, it takes no intelligence to understand that if I were UltraHighQPoints, I would not ask. Obviously, this is a very hard thing to think. I understand you!

    Sunday, August 12, 2018 2:46 PM
  • private decimal commisionRateEarning()
    {
       
    return grossSales * commissionRate;
    }

    Yes, yes, this is what exactly the author proposes. Yes, he says to do so, but it did not seem right to me, from a perspective of flux.

    Sunday, August 12, 2018 2:48 PM
  • Just have a look at the following snippet. There are used FirstName and LastName. Fine. The problem is that they are characterized as "autoimplemented" by the author, but how is their initialization possible, once: 

    1) never called and 

    2) how should for example FirstName knows that should use firstName and not lastName?

    (Chapter 10.7, Composition, Deitel)

    public class Employee
    {
       public string FirstName { get; private set; }   
       public string LastName { get; private set; }
       public Date BirthDate { get; private set; }
       public Date HireDate { get; private set; }
       // constructor to initialize name, birth date and hire date
       public Employee( string first, string last,
       Date dateOfBirth, Date dateOfHire )
       {
          firstName = first;
          lastName = last;
          birthDate = dateOfBirth;
          hireDate = dateOfHire;
     }// end Employee constructor
    
      // convert Employee to string format
      public override string ToString()
      {
         return string.Format( "{0}, {1} Hired: {2} Birthday: {3}", lastName, firstName, hireDate, birthDate );
      } // end method ToString
    } // end class
    

    Perhaps any mistype there? lastName instead of LastName or something in the constructor? But even a mistype happened, then how firstName and lastName would get initialized, and again, how FirstName and LastName auto-implementation should select which of the two (firstName, lastName) fit to these variables??


    Sunday, August 12, 2018 3:13 PM
  • This is more a philosophical question: Should I use properties in the internals of my classes or not?

    As OOP is about encapsulation of data and behavior with having a public interface and hidden internals, this means you can use properties in your internals as long as they don't transport information to the outside. Cause this would violate the hidden internals requirement.

    So, when we consider that the Console.WriteLine() calls in the property methods are a business requirement, then we cannot use the properties in our internal methods. Cause the would produce the same output. So this part of to code should look like:

    public string StringFormat()
    {
    	Console.WriteLine("* Inside StringFormat.");
    	return $"{"Commission rate"}: {this.firstName} {this.lastName}\n{"Social Security Number"}: {this.socialSecurityNumber}\n{"Gross sales"}: ${this.grossSales}\n{"Commission rate"}: {this.commissionRate:F2}\nEarnings: {this.CommisionRateEarning():F2}";
    }
    
    private decimal CommisionRateEarning()
    {
    	Console.WriteLine("* Inside CommisionRateEarning() get.");
    	return this.grossSales * this.commissionRate;
    }

    Resulting in

    While I think, that this should be the rule of thumb, it is not always true. Some projects may have simply different requirements.

    Entire sample:

    namespace ConsoleCS
    {
        using System;
    
        public class CommissionEmployee
        {
            private readonly string firstName;
            private readonly string lastName;
            private readonly string socialSecurityNumber;
            private decimal grossSales = 0;
            private decimal commissionRate = 0;
    
            public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber, decimal grossSales, decimal commissionRate)
            {
                Console.WriteLine("* Entering ctor..");
                this.firstName = firstName;
                this.lastName = lastName;
                this.socialSecurityNumber = socialSecurityNumber;
                this.GrossSales = grossSales;
                this.CommissionRate = commissionRate;
                Console.WriteLine("* Leaving ctor.");
            }
    
            public string FirstName
            {
                get
                {
                    Console.WriteLine("* Inside FirstName get.");
                    return this.firstName;
                }
            }
    
            public string LastName
            {
                get
                {
                    Console.WriteLine("* Inside LastName get.");
                    return this.lastName;
                }
            }
    
            public string SocialSecurityNumber
            {
                get
                {
                    Console.WriteLine("* Inside SocialSecurityNumber get.");
                    return this.socialSecurityNumber;
                }
            }
    
            public decimal GrossSales
            {
                get
                {
                    Console.WriteLine("* Inside GrossSales get.");
                    return this.grossSales;
                }
    
                set
                {
                    Console.WriteLine("* Inside GrossSales set.");
                    if (value >= 0)
                    {
                        this.grossSales = value;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("Gross Sales", value, "Gross Sales must be a non negative");
                    }
                }
            }
    
            public decimal CommissionRate
            {
                get
                {
                    Console.WriteLine("* Inside CommissionRate get.");
                    return this.commissionRate;
                }
    
                set
                {
                    Console.WriteLine("* Inside CommissionRate set.");
                    if (value >= 0 && value <= 1)
                    {
                        this.commissionRate = value;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("Commission Rate", value, "invalid Commission Rate value");
                    }
                }
            }
    
            public string StringFormat()
            {
                Console.WriteLine("* Inside StringFormat.");
                return $"{"Commission rate"}: {this.firstName} {this.lastName}\n{"Social Security Number"}: {this.socialSecurityNumber}\n{"Gross sales"}: ${this.grossSales}\n{"Commission rate"}: {this.commissionRate:F2}\nEarnings: {this.CommisionRateEarning():F2}";
            }
    
            private decimal CommisionRateEarning()
            {
                Console.WriteLine("* Inside CommisionRateEarning() get.");
                return this.grossSales * this.commissionRate;
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee emp1 = new CommissionEmployee("Sue", "Jones", "222-22-2222", 10000.00M, .06M);
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", emp1.StringFormat());
                Console.WriteLine();
                Console.WriteLine("Updating employee' s data:\nNew gross sales: 12000\nnew commission rate: 0.068\n");
                emp1.GrossSales = 12000.00M;
                emp1.CommissionRate = 0.068M;
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", emp1.StringFormat());
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }
    

    Sunday, August 12, 2018 3:24 PM
  • Man, go to check yourself. Your behavior is not ok. 

    Let me tell you one more thing and this is it with me. Do not ever bother me again.

    a) This is not a code production, even rubbish. This is YOUR conclusion and I can not (and I am not interested actually) tell from where and why such conclusion springs. 

    b) This is a study. Each time one revises a topic, more questions rise. Unless one does things mechanically, without thinking. You asked me something before and you already proved if you think or not.

    c) I suspect that there are much better programmers than you out there. For example, on Lumia phones there should have worked really A Class Chief programmers/engineers. But for a divine reason, the phone soundly failed. Windows (and Mac if you want my opinion) really crashed every often. I never liked Mac UI and I also did hate Windows crushing. It took somewhat 30 years for Microsoft to arrive to Win10 which I find lovely as an OS. All these years, in Apple, Sony, Microsoft, even Commodore, ZX etc, the best programmers would work. Some of those companies bankrupted. MS, Apple etc survived. Their engineers however, did not wake up one morning and started programming as if they had been 40 or 60 years in advance. They, obviously, digged the hole day by day. Science digs the hole day by day. To make it more presentational:

    d) From the day Greek Civilization put in order all previous knowledge, "one-man show" has died. To be a Physicist, you need Maths. To be a Computer guy, you need a whole army of Physicists and Mathematicians and micro/Engineers to make the whole theory behind and to create machines which will then create computers. Let us mention a few. Antiphon from Ramnousa and Vryson from Heraklea (around 5th century B.C.) used the exhaustion method in an attempt to square the circle. Aristotle demoted their attempt. But Archimedes appreciated their work the right way. It is however Appolonius Pergei to have done the most Magical work ever and go read Conical Sections original. Newton took the ideas of Archimedes and Appolonius Pergei and matched the with those of Tycho Brahe, giant Keppler et altri. Then came Gauss who used Newton's tools and gave solutions to Electromagnetism mainly (astronomy as well etc). Then came other guys like Young (double slit experiment, 1801), planet faced Mathematicians like Fourier or Laplace, then came a series of Giants (Kirchoff-> Maxwell-> Helmholtz -> BOLTZMANN, yes BOLTZMANN man, do you know what BOLTZMANN means?????? -> Wien -> Hertz -> Paschen et altri -> Planck who managed to match a set of "irrelevant" sciences. Then came some guys like Einstein -> Schottky, yes Schottky, what would you be without Schottky???? A complete ZERO. This you would be -> Bohr -> deBroglie -> experimentalists like Davinson and Germer-> Heizenberg -> Dirac -> Meitner, and an army of (Russian too) Scientists to set Humanity to a decent level. What would Computer Science be without the (physicist)Dennis Ritchie? To a decent level when one forgets how a clause works, it googles it and finds the answer. Do you know what would you (and all) be in a modern scientific world without googling? A perfect Z-E-R-O. Advanced programming (and science) cannot exist rapidly without googling, right Mr WiseAsshole? Unless you have von Neumann's memory. Do you have von Neumann's memory to remember E-V-E-R-Y-T-H-I-N-G by heart????? Do you know what man?? The rest of these scientists who followed them, are now near to create Quantum Computer. I will then see how good programmer you and others are. Since quite a lot of companies failed with compatible programming, imagine what a party there will  be with Quantum Programming. Why? Maybe they trust assholes like you again. Who knows...

    Get rid of me.






    Sunday, August 12, 2018 4:07 PM
  • a) No. ToString() is a general method to generate string output. It is the default method called when a string is required. It means, that you don't need any longer need to specify the method explicitly.

    E.g.

    CommissionEmployee emp1 = new CommissionEmployee("Sue", "Jones", "222-22-2222", 10000.00M, .06M);
    Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", emp1);

    b) A class encapsulates date and behavior. Class level variables are called fields. Fields which are private, but are used for properties, in their getters and setters, are called backing fields. Well, they back the property.

    I refactored your code, cause using abbreviations is a code smell. See clean code and opacity. Abbreviations are harder to read and understand. They should be only used when they are absolutely common for all users in that domain. I also refactored it, cause I think using common style rules makes code easier to read in the long term (nuget StyleCop.Analyzers).

    About using properties in the constructor (ctor):

    public CommissionEmployee(string f, string l, string ssn, decimal gSales, decimal cRate)
    {
        FirstName = f;
        LastName = l;
        SocialSecurityNumber = ssn;
        GrossSales = gSales;
        CommissionRate = cRate;
    }


    The problem is - see also the other answer about using properties vs fields in internal methods: the constructor should only construct an object instance. Nothing more. It should have no side effects in the domain. The additional output of the setters is such a side-effect. Of course, this is not a general rule, cause what a side-effect is depended on the domain your code is working and the requirements.

    Please copy code only from VS after successfully compiling it. Cause this would give you already  the answer to your question:

    It says "return fN". How is fN assigned a value??? This is why I asked for a diagram

    The code in the current, assumed state would not compile. Cause there is no setter for the FirstName property.

    c) Here again, we need to distinguish between backing fields and properties. After instantiating, all fields of a class are initialized. Either explicitly in the constructor or by using explicit default values or by using the data types implicit default values. E.g. like this:

    public class CommissionEmployee
    {
    	private readonly string firstName;
    	private readonly string lastName;
    	private readonly string socialSecurityNumber;
    	private decimal grossSales = 0;
    	private decimal commissionRate = 0;
    
    	public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber)
    	{
    		Console.WriteLine("* Entering ctor (1)..");
    		this.firstName = firstName;
    		this.lastName = lastName;
    		this.socialSecurityNumber = socialSecurityNumber;
    		Console.WriteLine("* Leaving ctor (1).");
    	}
    
    	public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber, decimal grossSales, decimal commissionRate)
    	{
    		Console.WriteLine("* Entering ctor (2)..");
    		this.firstName = firstName;
    		this.lastName = lastName;
    		this.socialSecurityNumber = socialSecurityNumber;
    		this.GrossSales = grossSales;
    		this.CommissionRate = commissionRate;
    		Console.WriteLine("* Leaving ctor (2).");
    	}
    
    	// []..]
    }

    As the backing fields for gross sales and commision rate have an explicit default value, we can add a  second ctor, which uses these. So we can use a simplified instantiation:

    public class Program
    {
    	public static void Main(string[] args)
    	{
    		CommissionEmployee employee2 = new CommissionEmployee("Hank", "Jones", "333-33-33");
    		Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", employee2);
    
    		Console.WriteLine("\nDone.");
    		Console.ReadLine();
    	}
    }
    

    which gives us this result:

    As properties consist of backing fields, getter and setter methods, we can only say that a property is initialized, when its backing fields are initialized. But this is only true from the plain compiler perspective. It is not true from the domain (business) view. Cause we have the concept of lazy initialization (using Lazy<T>) and proxy objects (proxy pattern) to enhance performance. Lazy property example using classic lazy initialization considering the creation of a Dummy instance is slow: 

    namespace ConsoleCS
    {
        using System;
    
        public class Dummy
        {
        }
    
        public class CommissionEmployee
        {
            private Dummy dummy;
    
            public Dummy Dummy
            {
                get
                {
                    if (this.dummy == null)
                    {
                        this.dummy = new Dummy();
                    }
    
                    return this.dummy;
                }
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee commissionEmployee = new CommissionEmployee();
                Console.WriteLine(commissionEmployee.Dummy);
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }
    

    The complete sample for the above scenarios without the lazy sample:

    namespace ConsoleCS
    {
        using System;
    
        public class CommissionEmployee
        {
            private readonly string firstName;
            private readonly string lastName;
            private readonly string socialSecurityNumber;
            private decimal grossSales = 0;
            private decimal commissionRate = 0;
    
            public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber)
            {
                Console.WriteLine("* Entering ctor (1)..");
                this.firstName = firstName;
                this.lastName = lastName;
                this.socialSecurityNumber = socialSecurityNumber;
                Console.WriteLine("* Leaving ctor (1).");
            }
    
            public CommissionEmployee(string firstName, string lastName, string socialSecurityNumber, decimal grossSales, decimal commissionRate)
            {
                Console.WriteLine("* Entering ctor..");
                this.firstName = firstName;
                this.lastName = lastName;
                this.socialSecurityNumber = socialSecurityNumber;
                this.GrossSales = grossSales;
                this.CommissionRate = commissionRate;
                Console.WriteLine("* Leaving ctor.");
            }
    
            public string FirstName
            {
                get
                {
                    Console.WriteLine("* Inside FirstName get.");
                    return this.firstName;
                }
            }
    
            public string LastName
            {
                get
                {
                    Console.WriteLine("* Inside LastName get.");
                    return this.lastName;
                }
            }
    
            public string SocialSecurityNumber
            {
                get
                {
                    Console.WriteLine("* Inside SocialSecurityNumber get.");
                    return this.socialSecurityNumber;
                }
            }
    
            public decimal GrossSales
            {
                get
                {
                    Console.WriteLine("* Inside GrossSales get.");
                    return this.grossSales;
                }
    
                set
                {
                    Console.WriteLine("* Inside GrossSales set.");
                    if (value >= 0)
                    {
                        this.grossSales = value;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("Gross Sales", value, "Gross Sales must be a non negative");
                    }
                }
            }
    
            public decimal CommissionRate
            {
                get
                {
                    Console.WriteLine("* Inside CommissionRate get.");
                    return this.commissionRate;
                }
    
                set
                {
                    Console.WriteLine("* Inside CommissionRate set.");
                    if (value >= 0 && value <= 1)
                    {
                        this.commissionRate = value;
                    }
                    else
                    {
                        throw new ArgumentOutOfRangeException("Commission Rate", value, "invalid Commission Rate value");
                    }
                }
            }
    
            public override string ToString()
            {
                Console.WriteLine("* Inside ToString().");
                return $"{"Commission rate"}: {this.firstName} {this.lastName}\n{"Social Security Number"}: {this.socialSecurityNumber}\n{"Gross sales"}: ${this.grossSales}\n{"Commission rate"}: {this.commissionRate:F2}\nEarnings: {this.CommisionRateEarning():F2}";
            }
    
            private decimal CommisionRateEarning()
            {
                Console.WriteLine("* Inside CommisionRateEarning().");
                return this.grossSales * this.commissionRate;
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee employee1 = new CommissionEmployee("Sue", "Jones", "222-22-2222", 10000.00M, .06M);
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", employee1);
                Console.WriteLine();
                Console.WriteLine("Updating employee' s data:\nNew gross sales: 12000\nnew commission rate: 0.068\n");
                employee1.GrossSales = 12000.00M;
                employee1.CommissionRate = 0.068M;
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", employee1);
    
                Console.WriteLine("\n---\n");
                CommissionEmployee employee2 = new CommissionEmployee("Hank", "Jones", "333-33-33");
                Console.WriteLine("\nAdvertise Employee 's data and earnings:\n{0}", employee2);
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    and its complete output:

    Sunday, August 12, 2018 4:12 PM
  • JESUS!!!! Thanx a lot Stefan. 
    Sunday, August 12, 2018 4:19 PM
  • Auto-implemented properites means that the compiler creates the backing field and the getter and setter during compile time in the IL only. Thus as consequence you cannot access the backing field directly. Cause the backing field created by the compiler is private and anonymous.

    1) Cause it is private and anonyoums, it is initialized to its default value and only changed when you access it by its setter.

    2) A auto-property is part of the C# syntax. Thus the language specifications define how it should be done. And the compiler does it according to them. So it's simply working by definition.

    p.s. again: Copy only code from VS after it has successfully compiled. This will give you more insight before asking.. cause the above class will not compile.

    Sunday, August 12, 2018 4:50 PM
  • Just as a reminder:

    Internal methods should only use side-effect free properties. As long as the requirements don't tell you to do it otherwise.

    But then, as a developer, you should at least discuss this. Cause it violates some basic ideas of OOP, especially encapsulation.

    Sunday, August 12, 2018 4:57 PM
  • You're welcome.
    Sunday, August 12, 2018 4:58 PM
  • Uhhh, okay, I have the feeling that this is my initial question, more or less.

    I commented out the public strings 

        //public string FirstName
        //{
        //    get
        //    {
        //        Console.WriteLine("* Inside FirstName get.");
        //        return this.firstName;
        //    }
        //}
    
        //public string LastName
        //{
        //    get
        //    {
        //        Console.WriteLine("* Inside LastName get.");
        //        return this.lastName;
        //    }
        //}
    
        //public string SocialSecurityNumber
        //{
        //    get
        //    {
        //        Console.WriteLine("* Inside SocialSecurityNumber get.");
        //        return this.socialSecurityNumber;
        //    }
        //}

    and the program runs as fine as previously. Then, why should one declare them? 

    Thanx a lot. 

    (Is it possible to translate return $"{"Commission rate"}: {this.firstName} {this.lastName}\n{"Social Security Number"}: {this.socialSecurityNumber}\n{"Gross sales"}: ${this.grossSales}\n{"Commission rate"}: {this.commissionRate:F2}\nEarnings: {this.CommisionRateEarning():F2}";
     ?? And I forgot to mention that the 1st to have created the first integrated computer with valves was the endeavorer Konrad Zusse who created Z3 around 1940. It was not ENIAC).

    Sunday, August 12, 2018 5:17 PM
  • and the program runs as fine as previously. Then, why should one declare them?

    Just because, we don't call it in the actual sample. Someone else might. E.g.

    namespace ConsoleCS
    {
        using System;
    
        public class CommissionEmployee
        {
            private readonly string firstName;
            private readonly string lastName;
    
            public CommissionEmployee(string firstName, string lastName)
            {
                Console.WriteLine("* Entering ctor..");
                this.firstName = firstName;
                this.lastName = lastName;
                Console.WriteLine("* Leaving ctor.");
            }
    
            public string FirstName
            {
                get
                {
                    Console.WriteLine("* Inside FirstName get.");
                    return this.firstName;
                }
            }
    
            public string LastName
            {
                get
                {
                    Console.WriteLine("* Inside LastName get.");
                    return this.lastName;
                }
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee emp1 = new CommissionEmployee("Sue", "Jones");
                Console.WriteLine($"{emp1.FirstName} {emp1.LastName}");
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    with 

    This part is the design part when developing. According to the requirements, you add the necessary properties to your class.

    return $"{"Commission rate"}: {this.firstName} {this.lastName}\n{"Social Security Number"}: {this.socialSecurityNumber}\n{"Gross sales"}: ${this.grossSales}\n{"Commission rate"}: {this.commissionRate:F2}\nEarnings: {this.CommisionRateEarning():F2}";
    is called string interpolation.


    Sunday, August 12, 2018 6:18 PM
  • Mr Stefan, you seem to be experienced programmer. I would like your opinion in this get;set; staff. In a variable like for example FirstName, one wouldn't expect a mechanism like the following one?

    public decimal GrossSales
    {       
            set
            {
                if (grossSales >= 0)
                {
                    Console.WriteLine("Inside GrossSales\\set\\if");
                    value = grossSales;
                }
                else
                {
                    Console.WriteLine("Inside GrossSales\\set\\else");
                    throw new ArgumentOutOfRangeException("Gross Sales", value, "Gross Sales must be a non negative");
                }
            }
            get { Console.WriteLine("Inside GrossSales\\get"); return value; }
        }

    You know, Constructor assigns a value for grossSales, then grossSales enters GrossSales, goes checked by the the set{} block and if the condition is fulfilled, then the value should be got by get{} block. 

    Instead, when we say  if(value >= 0), there is implied that value has (already) been assigned a value of another variable, as if 

    set
    {
         value = grossSales;
    
         if (value >= 0)
         {
               Console.WriteLine("Inside GrossSales\\set\\if");
               grossSales = value;
          }
          else.....
    }

    Doesn't this seem strange from a language designing perspective? I mean, we may omit set;get style and apply c++ style as that: 

    public class Time
    {
       private int h, m, s;
       public Time(int hour, int minute, int second)
       {
          SetTime(h, m, s);
       }
       public/private void SetTime(h, m, s) {//do some work}
    }

    What do you think? Thank you.

    Sunday, August 12, 2018 6:38 PM
  • The value variable is automatically declared in a setter. There it is of the type of the property and it contains the new value.

    So your snippet must look like:

    public decimal GrossSales
    {        
    	get 
    	{ 
    		Console.WriteLine("* Inside GrossSales get."); 
    		return value; 
    	}
    
    	set
    	{
    		if (value >= 0)
    		{
    			Console.WriteLine("* Inside GrossSales set.");
    			this.grossSales = value;
    		}
    	}
    }

    You should not throw exceptions in normal properties. See also Property Design. 

    If you need an exception, then you should consider using a method to set the value instead of a property.

    The other approach would be by accepting the wrong value but throwing the exception in a method where you access the backing fields. E.g.

    namespace ConsoleCS
    {
        using System;
    
        public class CommissionEmployee
        {
            public CommissionEmployee(string firstName, string lastName)
            {
                Console.WriteLine("* Entering ctor..");
                this.FirstName = firstName;
                this.LastName = lastName;
                Console.WriteLine("* Leaving ctor.");
            }
    
            public decimal CommissionRate { get; set; } = 0;
    
            public string FirstName { get; }
    
            public decimal GrossSales { get; set; } = 0;
    
            public string LastName { get; }
    
            public decimal CommisionRateEarning()
            {
                Console.WriteLine("* Inside CommisionRateEarning().");
                if (this.GrossSales < 0)
                {
                    throw new ArgumentException("Gross sales must be equal or greater than 0.");
                }
    
                return this.GrossSales * this.CommissionRate;
            }
    
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                CommissionEmployee emp1 = new CommissionEmployee("Sue", "Jones");
                Console.WriteLine($"{emp1.FirstName} {emp1.LastName}");
                try
                {
                    Console.WriteLine($"{emp1.CommisionRateEarning()}");
                }
                catch (Exception exception)
                {
                    Console.WriteLine($"! {exception.Message}");
                }
    
                emp1.GrossSales = -1;
                try
                {
                    Console.WriteLine($"{emp1.CommisionRateEarning()}");
                }
                catch (Exception exception)
                {
                    Console.WriteLine($"! {exception.Message}");
                }
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    Depending on the kind of class, like Time, where you have correlated backing fields. E.g.

    namespace ConsoleCS
    {
        using System;
    
        public class Time
        {
            private int hour;
            private int minute;
            private int second;
    
            public Time(int hour, int minute, int second)
            {
                this.SetTime(hour, minute, second);
            }
    
            public void SetTime(int hour, int minute, int second)
            {
                if (!(hour >= 0 && hour < 24) ||
                    !(minute >= 0 && minute < 60) ||
                    !(second >= 0 && second < 60))
                {
                    throw new ArgumentException("Incorrect parameters.");
                }
    
                this.hour = hour;
                this.minute = minute;
                this.second = second;
            }
    
            public override string ToString()
            {
                return $"{this.hour:00}:{this.minute:00}:{this.second:00}";
            }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                Time time = new Time(11, 12, 13);
                try
                {
                    Console.WriteLine($"{time}");
                    time.SetTime(12, 13, 14);
                    Console.WriteLine($"{time}");
                }
                catch (Exception exception)
                {
                    Console.WriteLine($"! {exception.Message}");
                }
    
                Console.WriteLine("\nDone.");
                Console.ReadLine();
            }
        }
    }

    Sunday, August 12, 2018 7:16 PM
  • Wow wow wow wow ha ha ha ha ha I cannot understand the text of the Property Design link. Schwierig, schwierig! One last thing I have to comment, based on your help and the link is that indeed, yesterday night I was given the impression that Properties assimilate to a method. On this basis, (and of course, modified according to the Property Design link, that is, no Exceptions inside set etc), the console output in my original question appears tolerable. 

    ------------------------------------------------------------------------------------------------------------

    Advertise Employee 's data and earnings://1
    Commission rate: Sue Jones//2
    Social Security Number: 222-22-2222//3
    Gross sales: $10000.00//4
    Commission rate: 0.06//5
    Earnings: 600.00//6

    Updating employee' s data://8
    New gross sales: 12000//9
    new commission rate: 0.068//10

    Inside GrossSales\set\if//1
    Inside CommissionRate\set\if//12
    Inside FirstName\get//13
    Inside LastName\get//14
    Inside SocialSecurityNumber\get//15
    Inside GrossSales\get//16
    Inside CommissionRate\get//17
    Inside GrossSales\get//18
    Inside CommissionRate\get//19

    Advertise Employee 's data and earnings://20
    Commission rate: Sue Jones
    Social Security Number: 222-22-2222
    Gross sales: $12000.00
    Commission rate: 0.07
    Earnings: 816.00

    -----------------------------------------------------------------------------------------------------------

    That is, in lines 11 and 12 the properties initialization occurs. Next, in lines 13-17 StringFormat() calls all five properties and the corresponding get{} blocks are energized. Nothing bad so far. In commissionEarnings(), two properties (GrossSales and CommissionRate) are again called (because, for example, the boss of the company -and not the engineer- orders so :) ) and thus the get{} blocks are energized again. It seems fine. 

    Of course, your proposal is more professional.  I also do not believe in 

    private decimal commisionRateEarning()
    {
        return grossSales * commissionRate;
    }

    Why should one use backing fields in a method? I believe more in 

    private decimal commisionRateEarning()
    {
        return GrossSales * CommissionRate;
    }

    I think that it is a strange explanation of the author of the book on this specific topic. Well Mr Stefan you helped me very very much. I will work on both ways, my original and mostly on yours.

    Thank you.

    Monday, August 13, 2018 8:21 AM
  • I found the answer to the whole circle. This guy explains it fine. https://www.youtube.com/watch?v=gvQziNULkdY

    @11:25 he clarifies it. So, in our example, when we say FirstName = fN; it is the value inside set{} that initially equals to fN and then the whole flux goes clear. Properties seem a little bit babbling, but that is for a good reason.

    And for God's (if any God) sake: set block should precede get block. 

    Cheers!!!



    Monday, August 13, 2018 1:34 PM
  • Man, are you sick?? Do you suffer from hallucinations or obsessions? I am asking because if so, I show compassion. DO I REPORT ANY PROBLEM ANYWHERE???? CANN' T YOU UNDERSTAND ENGLISH?  I SAY : "Hi there. I have a problem to understand the flux of the program. ".

    I COULD NOT UNDERSTAND THE FLUX OF THE PROBLEM.

    I DID NOT REPORT ANYTHING. 

    WHY THE FUCK DON'T YOU DO WHAT YOU WERE TOLD AND GET RID OF ME???? DO ME A FAVOR AND GO F.U.  

    Thursday, August 16, 2018 4:22 PM
  • Mr Stefan, may I ask you something please? I am actually wondering why in an auto-implemented clause where all backing variables are anonymous, one should declare set; as private; How one can access a hidden variable once he/she does not know which is it?

    For example

    public House
    {
       private set;
       get;
    }
    how could one access the anonymous variables? Thank you.

    Thursday, August 16, 2018 4:27 PM
  • The compiler knows how to access them. This is just how it works.

    The private, on the other side, change the way how you can use it. There are six visibilities:

    public, internal, protected, private, protected internal and private protected

    When you declare a property private, then you can only use it in the class, but not outside of it. The idea is, that this makes the property unchangeable from the outside. This used for properties which depend e.g. on complex calculations inside the class. Or for simple immutable properties.

    Friday, August 17, 2018 7:51 PM
  • Yes, yes, but I am referring to autocompletion Properties, not Properties where we use backing variables in set{} clause, and yes, in this case, no outside access is allowed. My question is why should one type the auto-completion set clause as private, once indeed "The compiler knows how to access them." and thus we have no idea what the private variable is. We do not see any backing variable in an auto-completion set{} clause. It is hidden, it is executed/used/processed in retroscene . So, why should we set the set{} clause as private?

    END OF QUESTIONS. Hope that you are all relieved. Sorry for being a jigger.  


    Saturday, August 18, 2018 1:54 PM