Home>

There is a class that uses a calculation method of an abstract class.
Temporarily succeeded Fruits
Apple, Mango, Banana.

MyNumber is given for individual identification.

Each fruit has a different formula.

Now, when I know only the identification number, I want to link an instance of the appropriate class and use the Culc method. Is that possible?
By the way, there are about 500 kinds of fruits.
I asked it because it seemed muddy to be tied manually.

How should the following hoge method be implemented?

Thanks for your response.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

public abstract class Fruits
{
    public virtual int MyNumber {get;}
    public abstract int Culc (int a, int b);
}
public class Apple: Fruits
{
    public override int MyNumber =>1;
    public override int Culc (int a, int b)
    {
        return a + b;
    }
}
public class Mango: Fruits
{
    public override int MyNumber =>2;
    public override int Culc (int a, int b)
    {
        return a-b * b;
    }
}
public class Banana: Fruits
{
    public override int MyNumber =>3;
    public override int Culc (int a, int b)
    {
        return a/b * 444;
    }
}

class MainClass
{
    static void Main ()
    {
        int whatIwant = 2;
        // Fruits someFruits = hoge (whatIWant);
        // I don't know what to do here
// I want to use Mango's Culc.
    }
}
c#
  • Answer # 1

    It's not a direct answer to the question, but I think there is a design error in how the ID number and fruit are linked.

    ■ Problem 1: Design numbers may be duplicated.
    Fruits inheritance classes (Apple, Mango, Banana) do not know each other's MyNumber, and there is a possibility of duplicate numbers by design.
    ■ Problem 2: Renumbering is difficult when changing
    For example, when you want to add Pear after Apple, you will need to shift the numbers written in over 500 classes one by one.
    MyNumber is not an instance but a class identification number, so it is not necessary to have it as a separate property.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    public abstract class Fruits
    {
        // As something that does not change dynamically
        public static readonly IReadOnlyDictionaryFruitsTypeDictionary =
            new Dictionary
            {
                {1, typeof (Apple)},
                {2, typeof (Mango)},
                {3, typeof (Banana)},
            };
        public static Fruits CreateInstance (int number)
            =>Activator.CreateInstance (FruitsTypeDictionary [number]) as Fruits;
        public abstract int Culc (int a, int b);
    }
    public class Apple: Fruits
    {
        public override int Culc (int a, int b) =>a + b;
    }
    public class Mango: Fruits
    {
        public override int Culc (int a, int b) =>a-b * b;
    }
    public class Banana: Fruits
    {
        public override int Culc (int a, int b) =>a/b * 444;
    }
    class MainClass
    {
        static void Main ()
        {
            int whatIwant = 2;
            var someFruits = Fruits.CreateInstance (whatIwant);
            Console.WriteLine (someFruits.Culc (10, 20));
            Console.ReadKey ();
        }
    }

    Furthermore, as long as you look at the contents of the question, Calc does not refer to any field, and even if you see what you are trying to do, you can use the Calc selectively by creating a new instance from whatIwant , So the structure of inheriting an abstract class may be unnecessary.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    public enum Fruits
    {
        Apple = 1,
        Mango = 2,
        Banana = 3,
    }
    public static class FruitsCalculator
    {
        // Since there is no way to go, make it static, but if there is an appropriate place, there.
        public static int Calc (Fruits fruits, int a, int b)
        {
            switch (fruits)
            {
                case Fruits.Apple:
                    return a + b;
                case Fruits.Mango:
                    return a-b * b;
                case Fruits.Banana:
                    return a/b * 444;
                default:
                    throw new ArgumentException ("Undifined fruits.", nameof (fruits));
            }
        }
    }
    class MainClass
    {
        static void Main ()
        {
            int value = FruitsCalculator.Calc ((Fruits) 2, 10, 20);
            Console.WriteLine (value);
            Console.ReadKey ();
        }
    }

    I'm sorry if I don't know the background of the assignment.

  • Answer # 2

    I think it's better to do it manually, but here are some examples.

    The flow is
    Get all types in assembly

    Check if type/instance is derived class

    Create an instance from Type

    I'm doing it.

    If you want to search many times, you should generateDictionary, etc., and use it once more.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;namespace ConsoleApplication1
    {
        public abstract class Fruits
        {
            public virtual int MyNumber {get;}
            public abstract int Culc (int a, int b);
        }
        public class Apple: Fruits
        {
            public override int MyNumber =>1;
            public override int Culc (int a, int b)
            {
                return a + b;
            }
        }
        public class Mango: Fruits
        {
            public override int MyNumber =>2;
            public override int Culc (int a, int b)
            {
                return a-b * b;
            }
        }
        public class Banana: Fruits
        {
            public override int MyNumber =>3;
            public override int Culc (int a, int b)
            {
                return a/b * 444;
            }
        }
        class Program
        {
            static void Main (string [] args)
            {
                // enumerate all classes
                foreach (var type in System.Reflection.Assembly.GetExecutingAssembly (). GetTypes ())
                {
                    // Extract only Fruits subclass
                    if (type.IsSubclassOf (typeof (Fruits)))
                    {
                        var fruits = (Fruits) Activator.CreateInstance (type);// Instantiate
                        if (fruits.MyNumber == 2)
                        {
                            Console.WriteLine ($"calc = {fruits.Culc (123, 456)}");
                        }
                    }
                }
            }
        }
    }

Trends