Link to home
Start Free TrialLog in
Avatar of IzzyTwinkly
IzzyTwinklyFlag for United States of America

asked on

property-based initialization.

Hi experts,

from the code below, Initializing Product looks little bit different from what I have done.
1. In GetSampleProducts(), return statement comes first.
2. Also it uses {} instead of () to initialize each product.
3. we need a private parameterless constructor Product(){}.

I guess that it's because it uses properties instead instance variable. Can anybody explain these in more detail please?

class Product
    {
        public string Name { get; private set; }
        public decimal Price { get; private set; }
       
        public Product(string name, decimal price)
        {
            Name = name;
            Price = price;
        }

        Product() { }
        public static List<Product> GetSampleProducts()
        {
            return new List<Product>
            {
                new Product {Name ="West Side Stroy", Price = 9.99m},
                new Product {Name = "Assassins", Price = 14.99m},
                new Product {Name = "Frogs", Price = 13.99m},
                new Product {Name = "Sweeney Todd", Price = 10.99m}
            };
        }
}

Open in new window

Avatar of it_saige
it_saige
Flag of United States of America image

1.  To answer this question, you must understand that:
public static List<Product> GetSampleProducts()
{
	return new List<Product>
	{
		new Product {Name ="West Side Stroy", Price = 9.99m},
		new Product {Name = "Assassins", Price = 14.99m},
		new Product {Name = "Frogs", Price = 13.99m},
		new Product {Name = "Sweeney Todd", Price = 10.99m}
	};
}

Open in new window

Logically is the same as:
public static List<Product> GetSampleProducts()
{
	List<Product> results = new List<Product>();
	results.Add(new Product { Name = "West Side Stroy", Price = 9.99m });
	results.Add(new Product {Name = "Assassins", Price = 14.99m});
	results.Add(new Product {Name = "Frogs", Price = 13.99m});
	results.Add(new Product { Name = "Sweeney Todd", Price = 10.99m });
	return results;
}

Open in new window


2. The bracket's define a initialization process.  Think of this as the same thing as:
int a = 5;

Open in new window

The difference here is that you are initializing a reference item, so you have to tell the initializer which property[ or properties] you are declaring the value for.

3.  A parameter less constructor is needed if you plan on declaring a new instance of a class without passing parameters and have an existing constructor defined that accepts parameters.  The fact that the parameter less constructor is marked private simply means that anything outside of the Product class cannot declare a new instance without using the constructor that accepts parameters.

-saige-
So lets have a little fun with your code:
using System;
using System.Collections.Generic;
using System.Linq;

namespace EE_Q28705107
{
	class Program
	{
		static void Main(string[] args)
		{
			var products = Product.GetSampleProducts();
			// I'm going to add a new Product to my products list.
			products.Add(new Product("Mad Max", 49.99m) { Quantity = 5 });
			foreach (var product in products)
				Console.WriteLine(product);

			Console.WriteLine(Product.Checkout(products));
			Console.ReadLine();
		}
	}

	class Product
	{
		public string Name { get; private set; }
		public decimal Price { get; private set; }
		public int Quantity { get; set; }
		public decimal Total { get { return Price * Quantity; } }

		public Product(string name, decimal price)
		{
			Console.WriteLine("IN CONSTRUCTOR WITH PARAMETERS");
			Name = name;
			Price = price;
		}

		Product() 
		{
			Console.WriteLine("IN PARAMETERLESS CONSTRUCTOR");
		}

		public static List<Product> GetSampleProducts()
		{
			return new List<Product>
			{
				new Product { Name = "West Side Stroy", Price = 9.99m, Quantity = 1 },
				new Product { Name = "Assassins", Price = 14.99m, Quantity = 2 },
				new Product { Name = "Frogs", Price = 13.99m, Quantity = 1 },
				new Product { Name = "Sweeney Todd", Price = 10.99m, Quantity = 2 }
			};
		}

		public static string Checkout(IEnumerable<Product> products)
		{
			return string.Format("Total cost: {0:C2}", products.Sum(x => x.Total));
		}

		public override string ToString()
		{
			return string.Format("{0} of {1} at {2:C2} = {3:C2}", Quantity, Name, Price, Total);
		}
	}
}

Open in new window

Produces the following output -User generated image-saige-
Avatar of IzzyTwinkly

ASKER

Thanks Saige!

I am still little bit confused.
In your answer for question 3, you said, "A parameter less constructor is needed if you plan on declaring a new instance of a class without passing parameters and have an existing constructor defined that accepts parameters. "

When we do 'new Product {Name ="West Side Stroy", Price = 9.99m}', I thought that we are passing 2 parameters. But it seems that this line calls parameterless constructor, right?
hum...
ASKER CERTIFIED SOLUTION
Avatar of it_saige
it_saige
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
To further prove my point, let's say we now decide we don't want to define a constructor that accepts parameters, matter of fact, we don't want to define any constructors of any kind.  What do you think will happen now?

Well let's find out -User generated imageIt appears as if the compiler does not like that we are trying to use a constructor.  But remember a class (by default) does not need a constructor/destructor as an implied public, parameter-less, constructor/destructor is generated by default.  Let's test that theory by trying to just initialize our instances with a parameter-less constructor.User generated imageUh-oh now we got a new error.  The implied constructor is public but the accessors (the setters) for two of the properties (Name and Price) are not.  These are marked as private, this means that only a class defined method can access the properties.  So we can do one of a few things:
1,  We can make the setters public by removing the private declaration.
2.  We can create a new constructor that takes the parameters.
3.  We can create a method that allows us to set the parameters.

For the sake of simplicity, let's remove the private declaration from the property setters (I will leave you with the third option as we have already proven the second option works).
And once again, everything is right in the world -User generated imageNow let's run it and see what output we get -User generated imageAnd finally here is the updated code -
using System;
using System.Collections.Generic;
using System.Linq;

namespace EE_Q28705107
{
	class Program
	{
		static void Main(string[] args)
		{
			var products = Product.GetSampleProducts();
			// I'm going to add a new Product to my products list.
			products.Add(new Product { Name = "Mad Max", Price = 49.99m, Quantity = 5 });
			foreach (var product in products)
				Console.WriteLine(product);

			Console.WriteLine(Product.Checkout(products));
			Console.ReadLine();
		}
	}

	class Product
	{
		public string Name { get; set; }
		public decimal Price { get; set; }
		public int Quantity { get; set; }
		public decimal Total { get { return Price * Quantity; } }

		// Uh-oh, no constructors defined...
		//public Product(string name, decimal price)
		//{
		//     Console.WriteLine("IN CONSTRUCTOR WITH PARAMETERS");
		//     Name = name;
		//     Price = price;
		//}

		// Removed parameter-less constructor
		//Product()
		//{
		//     Console.WriteLine("IN PARAMETERLESS CONSTRUCTOR");
		//}

		public static List<Product> GetSampleProducts()
		{
			return new List<Product>
			{
				new Product { Name = "West Side Stroy", Price = 9.99m, Quantity = 1 },
				new Product { Name = "Assassins", Price = 14.99m, Quantity = 2 },
				new Product { Name = "Frogs", Price = 13.99m, Quantity = 1 },
				new Product { Name = "Sweeney Todd", Price = 10.99m, Quantity = 2 }
			};
		}

		public static string Checkout(IEnumerable<Product> products)
		{
			return string.Format("Total cost: {0:C2}", products.Sum(x => x.Total));
		}

		public override string ToString()
		{
			return string.Format("{0} of {1} at {2:C2} = {3:C2}", Quantity, Name, Price, Total);
		}
	}
}

Open in new window

-saige-
And finally, to further illustrate that we are not using a constructor but, rather, initializing properties, let's say we remove the Quantity property initialization on the Product instances that are created by the GetSampleProducts() method [remember we are still using the implied public parameter-less constructor].  What do you think happens then?
using System;
using System.Collections.Generic;
using System.Linq;

namespace EE_Q28705107
{
	class Program
	{
		static void Main(string[] args)
		{
			var products = Product.GetSampleProducts();
			// I'm going to add a new Product to my products list.
			products.Add(new Product { Name = "Mad Max", Price = 49.99m, Quantity = 5 });
			foreach (var product in products)
				Console.WriteLine(product);

			Console.WriteLine(Product.Checkout(products));
			Console.ReadLine();
		}
	}

	class Product
	{
		public string Name { get; set; }
		public decimal Price { get; set; }
		public int Quantity { get; set; }
		public decimal Total { get { return Price * Quantity; } }

		// Uh-oh, no constructors defined...
		//public Product(string name, decimal price)
		//{
		//     Console.WriteLine("IN CONSTRUCTOR WITH PARAMETERS");
		//     Name = name;
		//     Price = price;
		//}

		// Removed parameter-less constructor
		//Product()
		//{
		//     Console.WriteLine("IN PARAMETERLESS CONSTRUCTOR");
		//}

		public static List<Product> GetSampleProducts()
		{
			return new List<Product>
			{
				new Product { Name = "West Side Stroy", Price = 9.99m },
				new Product { Name = "Assassins", Price = 14.99m },
				new Product { Name = "Frogs", Price = 13.99m },
				new Product { Name = "Sweeney Todd", Price = 10.99m }
			};
		}

		public static string Checkout(IEnumerable<Product> products)
		{
			return string.Format("Total cost: {0:C2}", products.Sum(x => x.Total));
		}

		public override string ToString()
		{
			return string.Format("{0} of {1} at {2:C2} = {3:C2}", Quantity, Name, Price, Total);
		}
	}
}

Open in new window

Produces the following output -User generated image-saige-
Wow. Thanks for your time and explanation!!!