简体   繁体   中英

How to instantiate a generic list without knowing the type

I created a method to organize a generic list without know the type, it will sort if its int or decimal.

However the code that retrieves the values from textboxes uses List

I tried to convert it to List, but it doesnt work. I want this code to work if they type integers or decimals or strings in the textboxes.

This was part of an interview question where they asked not to use the sort method, and that the input should receive for example INTS or DECIMALS

private void btnSort_Click(object sender, EventArgs e)
        {
            List<int> list = new List<int>();
            list.Add(int.Parse(i1.Text));
            list.Add(int.Parse(i2.Text));
            list.Add(int.Parse(i3.Text));
            list.Add(int.Parse(i4.Text));
            list.Add(int.Parse(i5.Text));
            Sort(list);
            StringBuilder sb = new StringBuilder();
            foreach (int t in list)
            {
                sb.Append(t.ToString());
                sb.AppendLine();
            }
            result.Text = sb.ToString();
        }


        private void Sort<T>(List<T> list)
        {
            bool madeChanges;
            int itemCount = list.Count;
            do
            {
                madeChanges = false;
                itemCount--;
                for (int i = 0; i < itemCount; i++)
                {
                    int result = Comparer<T>.Default.Compare(list[i], list[i + 1]);

                    if (result > 0)
                    {
                        Swap(list, i, i + 1);
                        madeChanges = true;
                    }
                }
            } while (madeChanges);
        }


        public List<T> Swap<T>(List<T> list,
                int firstIndex,
                int secondIndex)
        {
            T temp = list[firstIndex];
            list[firstIndex] = list[secondIndex];
            list[secondIndex] = temp;

            return list;
        }

I wanted that something like this: but gives error Error 1 The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?) c:\\users\\luis.simbios\\documents\\visual studio 2010\\Projects\\InterViewPreparation1\\InterViewPreparation1\\Generics\\GenericsSorting1.cs 22 18 InterViewPreparation1

List list = new List(); list.Add(i1.Text); list.Add(i2.Text); Sort(list);

because its an interview question in which they asked not to use the sort method.

In this case you can add a generic constraint IComparable<T> and then use the CompareTo() method:

 private void Sort<T>(List<T> list) where T : IComparable<T>
 {
    //...
 }

Edit:

You would have to write custom code to determine whether the input is string, int or decimal, ie use TryParse(..) - this will be very fragile though. Once you do know the type (one way or another) you can use MakeGenericType() and Activator.CreateInstance() to create your List<T> object at run time and then use MakeGenericMethod() to call your generic method:

Type type = typeof(string);
IList list = (IList) Activator.CreateInstance(typeof(List<>).MakeGenericType(type));
//add items to list here

var p = new Program();
MethodInfo method = typeof(Program).GetMethod("Sort");
MethodInfo genericMethod = method.MakeGenericMethod(new Type[] { type });
genericMethod.Invoke(p, new [] {list} );

I am pretty sure that is not what the interview question intended to ask for.

First, as Jason points out, let the platform do the work for you - call .Sort.

Second, it looks to me like you're going to have to select the 'T' of the List based on examining the contents of the textboxes so you can handle ints vs. strings, etc. And then assign items to the list based on that. But once you have decided, your sort won't care.

You're not going about this the right way. Embrace generics correctly. What you want is this:

public string Foo<T>(IEnumerable<string> strings) where T : struct, IComparable<T> {
    var list = strings.Select(s => (T)Convert.ChangeType(s, typeof(T))).ToList();
    list.Sort((x, y) => (x.CompareTo(y)));
    return String.Join("\n", list);
}

Now you can say

string response = Foo<int>(strings);

or

string response = Foo<decimal>(strings);

depending on which you want.

Note that

  1. We use List<T>.Sort to do the sorting.
  2. We use String.Join to build the string to display back to the user.

This should compile, but please excuse trivial errors if it doesn't. I can't fire up the ol' compiler right now.

Edit: I see you edited in that you can't use List<T>.Sort . It's easy enough to replace my use of List<T>.Sort with your own implementation.

Try something like:

private static IList foobar(Type t) 
{ 
  var listType = typeof(List<>); 
  var constructedListType = listType.MakeGenericType(t); 
  var instance = Activator.CreateInstance(constructedListType); 
  return (IList)instance; 
}

Then use:

IList list = foobar(TYPE); 

Where TYPE is the type that you want you list to be.

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM