Home>

Create a constructor that takes several different arguments in one class
I want to be able to call the corresponding method, but I don't know how to do it.
Before that, I'm not sure if this is feasible, so please answer.

Specific content
__ // Correction __
public class A
{
   private int ListSize = 5;
   private List<string>StrList;
   private List<float>FloatList;
   public A () {
Initialization content;
   }
   public A (string str) {
// Create the contents of the list for ListSize
For (var i = 0;i<ListSize;i ++) StrList.add ("");
   }
   public A (float value) {
// Create the contents of the list for ListSize
For (var i = 0;i<ListSize;i ++) FloatList.add (0);
   }
   public Method () {
    Processing using the initialization contents of A ();
   }
   public Method (string str) {
   // Create a StrList that holds the latest 5 strs for each execution

   }
   public Method (float value) {
    // Create a FloatList that holds the latest 5 values ​​for each execution
   }
}


As a concrete content, we are currently applying the same processing to numbers of different types (Vector3/Quaternion/float).
Therefore, I would like to standardize the processing, but I thought about creating a type division class to apply the processing, and thought about the above class.
However, in the above example, if you instantiate with A (string str) and you can use the Method (string str) method, there is no problem, but if you make a mistake in the argument and execute Method (float value), think.
This may be fine if you're doing it yourself, but it's a problem if you're using this class with a large number of people.
I wondered if the constructor used there couldn't enable the method, or if the classes should be separated in the first place.
Thank you.

* Addition
As a usage assumption, I want to always have the latest value for ListSize every time update () is called in unity.

  • Answer # 1

    Why not try using a generic class (ClassName)?
    You can specify the type when instantiating.

    public class MyClass<T>{
        public MyClass (T arg)
        {
            ...
        }
        public void MyMethod (T arg)
        {
            ...
        }
    }
    class MainClass
    {
        static void Main (string [] args)
        {
            MyClass<string>a = new MyClass<string>("hoge");
            a.MyMethod ("aaa");
        }
    }

  • Answer # 2

    If you instantiate with A (string str) and use the method of Method (string str), there is no problem, but I think that you may execute Method (float value) with the wrong argument.

    Designers of this class should add XML comments.
    Users of this class should read it and pass the intended arguments when creating the instance.

    If you are using Visual Studio, you can see the contents of the XML comment and the arguments you are passing by hovering over the description of the constructor call.

    If the user is conscious of reading and using the document, there is no mistake.
    Without that awareness, I doubt if I am a programmer in the first place.

    See the Convert class.ToByteMethod,ToBooleanMethods etc. are overloaded a lot, but if you read the documentation, you will not make a mistake by passing arguments.

    So unless you're too tired, programmers shouldn't accidentally use it, so it doesn't matter.

    If suzuki0707 writes a document and the user has a complicated structure that makes them misunderstand even if they read it, I think that you should consider means such as dividing the class.

    Is it possible for the constructor used to enable the method?

    I can't because it's not in the language specifications. It is judged that it is not necessary.


    Isn't it possible to do what you want with the code provided by having a fixed-length collection that holds only the latest elements that can be specified generically?

    I made it as a trial.

    public class FixedLengthList<T>: IList<T>{
        private readonly List<T>_list;
        private readonly int _size;
        public FixedLengthList (int size)
        {
            _list = new T [size] .ToList ();
            this._size = size;
        }
        public T this [int index]
        {
            get =>_list [index];
            set =>_list [index] = value;
        }
        public int Count =>_list.Count;
        public bool IsReadOnly =>((IList<T>) _ list) .IsReadOnly;
        public void Add (T element)
        {
            if (_list.Count ()>_size){
                _list.RemoveAt (0);
            }
            _list.Add (element);
        }
        public void Clear ()
        {
            _list.Clear ();
        }
        public bool Contains (T item)
        {
            return _list.Contains (item);
        }
        public void CopyTo (T [] array, int arrayIndex)
        {
            _list.CopyTo (array, arrayIndex);
        }
        public IEnumerator<T>GetEnumerator ()
        {
            return ((IList<T>) _ list) .GetEnumerator ();
        }
        public int IndexOf (T item)
        {
            if (index>= _size)
            {
                throw new IndexOutOfRangeException ();
            }
            return _list.IndexOf (item);
        }
        public void Insert (int index, T item)
        {
            _list.Insert (index, item);
        }
        public bool Remove (T item)
        {
            return _list.Remove (item);
        }
        public void RemoveAt (int index)
        {
            _list.RemoveAt (index);
        }
        IEnumerator IEnumerable.GetEnumerator ()
        {
            return ((IList<T>) _ list) .GetEnumerator ();
        }
    }

    Then the A class becomes very simple.

    public class A
    {
        private const int ListSize = 5;
        private FixedLengthList<string>_strList = new FixedLengthList<string>(ListSize);
        private FixedLengthList<float>_floatList = new FixedLengthList<float>(ListSize);
    }

    This will avoid the original problem with this question.

  • Answer # 3

    If you can solve it with a generic class, you should use it, and if you think that you will "wrongly do XX", you will not be able to do anything.
    If this is the case, why not set the flag yourself as shown below?

    class A
    {private int mytype;
        public A ()
        {
            mytype = 0;
            // Initialization A
        }
        public A (string value)
        {
            mytype = 1;
            // Initialization B
        }
        public A (float value)
        {
            mytype = 2;
            // Initialization C
        }
        public void Method ()
        {
            if (mytype! = 0)
            {
                throw new ArgumentException ("type is wrong");
            }
            // Process A
        }
        public void Method (string value)
        {
            if (mytype! = 1)
            {
                throw new ArgumentException ("type is wrong");
            }
            // Process B
        }
        public void Method (float value)
        {
            if (mytype! = 2)
            {
                throw new ArgumentException ("type is wrong");
            }
            // Process C
        }
    }

  • Answer # 4

    If you call Method () with the wrong argument, why not throw an exception?

    NullReferenceException mercilessly flies:

    class A
    {
        public A () {m_method = this.Method_;}
        public A (string str) {m_method_s = this.Method_s;}
        public A (float value) {m_method_f = this.Method_f;}
        public void Method () {m_method ();}
        public void Method (string str) {m_method_s (str);}
        public void Method (float value) {m_method_f (value);}
        private readonly Action m_method = null;
        private readonly Action<string>m_method_s = null;
        private readonly Action<float>m_method_f = null;
        private void Method_ () {Console.WriteLine ("Method ()");}
        private void Method_s (string str) {Console.WriteLine (str);}
        private void Method_f (float value) {Console.WriteLine (value);}
    }