none
Generic use is not clear in one program RRS feed

  • Question

  • see this class code

        public class ShipperFactory
        {
            private static TShip Create<TShip>()
                where TShip : IShip, // interface contract constraint
                new() // public parameter-less constructor constraint
            {
                return new TShip();
            }
    
            public static readonly IDictionary<Shipper, Func<IShip>> Creators =
                new Dictionary<Shipper, Func<IShip>>()
            {
                { Shipper.UPS, () => Create<ShipperUPS>() },
                { Shipper.FedEx, () => Create<ShipperFedEx>() },
                { Shipper.Purolator, () => Create<ShipperPurolator>() }
            };
    
            public static IShip CreateInstance(Shipper enumModuleName)
            {
                return Creators[enumModuleName]();
            }
        }

    specially the below code is not clear where

            public static readonly IDictionary<Shipper, Func<IShip>> Creators =
                new Dictionary<Shipper, Func<IShip>>()
            {
                { Shipper.UPS, () => Create<ShipperUPS>() },
                { Shipper.FedEx, () => Create<ShipperFedEx>() },
                { Shipper.Purolator, () => Create<ShipperPurolator>() }
            };

    1) see this line whose meaning is not clea. what is the meaning of Func<IShip> ?

    new Dictionary<Shipper, Func<IShip>>()

    Dictionary usage is not clear. help me to understand the code of Dictionary and as well as ShipperFactory class.

    it is required to use both interface and abstract class ? is it not redundant here ?

    here giving the full code which show how i am using ShipperFactory class

    clalling like this way
    --------------------------        
    
    	private void btnUPS_Click(object sender, EventArgs e)
            {
                ShipperFactory.CreateInstance(Shipper.UPS).Ship();
            }
    
            private void btnFedEx_Click(object sender, EventArgs e)
            {
                ShipperFactory.CreateInstance(Shipper.FedEx).Ship();
            }
    
            private void btnPurolator_Click(object sender, EventArgs e)
            {
                ShipperFactory.CreateInstance(Shipper.Purolator).Ship();
            }
    
        public enum Shipper
        {
            UPS,
            FedEx,
            Purolator
        }
    
        public interface IShip
        {
            void Ship();
        }
    
        public abstract class ShipperBase : IShip
        {
            //Etc
            public abstract void Ship();
    
        }
    
        public class ShipperUPS : ShipperBase
        {
            public override void Ship()
            {
                //-- code logic to implement shipping method for Purolator
                MessageBox.Show("UPS ship start");
            }
        }
    
        public class ShipperFedEx : ShipperBase
        {
            public override void Ship()
            {
                //-- code logic to implement shipping method for Purolator
                MessageBox.Show("FedEX ship start");
            }
        }
    
        public class ShipperPurolator : ShipperBase
        {
            public override void Ship()
            {
                //-- code logic to implement shipping method for Purolator
                MessageBox.Show("Purolator ship start");
            }
        }
    
        public class ShipperFactory
        {
            private static TShip Create<TShip>()
                where TShip : IShip, // interface contract constraint
                new() // public parameter-less constructor constraint
            {
                return new TShip();
            }
    
            public static readonly IDictionary<Shipper, Func<IShip>> Creators =
                new Dictionary<Shipper, Func<IShip>>()
            {
                { Shipper.UPS, () => Create<ShipperUPS>() },
                { Shipper.FedEx, () => Create<ShipperFedEx>() },
                { Shipper.Purolator, () => Create<ShipperPurolator>() }
            };
    
            public static IShip CreateInstance(Shipper enumModuleName)
            {
                return Creators[enumModuleName]();
            }
        }
    looking for help. thanks



    Tuesday, April 11, 2017 12:26 PM

Answers

  • If you don't know about generics in C#, that read up on that first. Follow this link or just search for "C# generics".

    A Func<T> is a generic type of a delegate (basically, a function) that takes no arguments and returns a value of type T.

    Hence Func<string> represents a method that returns a string. Func<int> represents a method that returns an int. And Func<IShip> is a method that returns an IShip.

    A Dictionary<TKey, TValue> is a generic dictionary that takes keys of type TKey and values of type TValue. Hence if you declare a dictionary of type Dictionary<int, string> you are declaring a dictionary where the keys are ints and the values are string.

    In your example you have a Dictionary<Shipper, Func<IShip>>. This is a dictionary where the keys are of type Shipper (an enumerated type) and the values are methods that return IShip.

    This dictionary is populated when it is declared in this code:

     public static readonly IDictionary<Shipper, Func<IShip>> Creators =
                new Dictionary<Shipper, Func<IShip>>()
            {
                { Shipper.UPS, () => Create<ShipperUPS>() },
                { Shipper.FedEx, () => Create<ShipperFedEx>() },
                { Shipper.Purolator, () => Create<ShipperPurolator>() }
            };

    So Creators is a dictionary that maps the Shipper enumerated type to methods that return an IShip.

    Specifically, the Shipper.UPS key will return a method that calls Create<ShipperUPS> (a generic method that returns a ShipperUPS object) and so on.

    The ShipperBase class is abstract because it makes no sense to create an object of type ShipperBase. You only want people to create types that descend from this base class (a ShipperUPS, and ShipperFedEx and so on).

    So to put it all together:

    You have a factory class ShipperFactory with a public function CreateInstance that requires you to pass in a value of the enumerated type Shipper indicated which kind of Shipper??? class you want.

    This then looks up in the Creators dictionary for the method matching this Shipper enumerated type.

    It then calls that method in order to generate and return the required class.

    The previous two steps are all combined into the single line:

    return Creators[enumModuleName]();

    If it's any easier to think about, that previous line can be rewritten as:

    // Get function that creates the type I want
    Func<IShip> creatorFunction = Creators[enumModuleName];
    
    // Call the function to get the type and return it
    return creatorFunction();

    • Proposed as answer by Ryan Software Tuesday, April 11, 2017 4:52 PM
    • Marked as answer by Mou_kolkata Wednesday, April 12, 2017 2:50 PM
    Tuesday, April 11, 2017 12:43 PM

All replies

  • If you don't know about generics in C#, that read up on that first. Follow this link or just search for "C# generics".

    A Func<T> is a generic type of a delegate (basically, a function) that takes no arguments and returns a value of type T.

    Hence Func<string> represents a method that returns a string. Func<int> represents a method that returns an int. And Func<IShip> is a method that returns an IShip.

    A Dictionary<TKey, TValue> is a generic dictionary that takes keys of type TKey and values of type TValue. Hence if you declare a dictionary of type Dictionary<int, string> you are declaring a dictionary where the keys are ints and the values are string.

    In your example you have a Dictionary<Shipper, Func<IShip>>. This is a dictionary where the keys are of type Shipper (an enumerated type) and the values are methods that return IShip.

    This dictionary is populated when it is declared in this code:

     public static readonly IDictionary<Shipper, Func<IShip>> Creators =
                new Dictionary<Shipper, Func<IShip>>()
            {
                { Shipper.UPS, () => Create<ShipperUPS>() },
                { Shipper.FedEx, () => Create<ShipperFedEx>() },
                { Shipper.Purolator, () => Create<ShipperPurolator>() }
            };

    So Creators is a dictionary that maps the Shipper enumerated type to methods that return an IShip.

    Specifically, the Shipper.UPS key will return a method that calls Create<ShipperUPS> (a generic method that returns a ShipperUPS object) and so on.

    The ShipperBase class is abstract because it makes no sense to create an object of type ShipperBase. You only want people to create types that descend from this base class (a ShipperUPS, and ShipperFedEx and so on).

    So to put it all together:

    You have a factory class ShipperFactory with a public function CreateInstance that requires you to pass in a value of the enumerated type Shipper indicated which kind of Shipper??? class you want.

    This then looks up in the Creators dictionary for the method matching this Shipper enumerated type.

    It then calls that method in order to generate and return the required class.

    The previous two steps are all combined into the single line:

    return Creators[enumModuleName]();

    If it's any easier to think about, that previous line can be rewritten as:

    // Get function that creates the type I want
    Func<IShip> creatorFunction = Creators[enumModuleName];
    
    // Call the function to get the type and return it
    return creatorFunction();

    • Proposed as answer by Ryan Software Tuesday, April 11, 2017 4:52 PM
    • Marked as answer by Mou_kolkata Wednesday, April 12, 2017 2:50 PM
    Tuesday, April 11, 2017 12:43 PM
  • tell me the code what i posted here is factory method pattern or is it abstract factory pattern ?

    how to create a two functions with Func<T> one function accept a generic type and return void and another one accept a generic type & return generic type.

    please give me two generic function sample. thanks

    Wednesday, April 12, 2017 2:52 PM