0

I have a generic class and I take its type as a parameter type e.g. int for a method in my class like below:

public class UnlimitedGenericArray<T>
{
 private void InsertItem(T item)
 {
  this.array[0] = item;
 }
}

Now, when I want to invoke the InsertItem()from a console application for example how can I know the argument's type at runtime?

    static void Main(string[] args)
    {
        UnlimitedGenericArray<int> oArray = new UnlimitedGenericArray<int>();
        while(true)
        {
         var userInput = Console.Readline();
         oArray.InsertItem(userInput);
        }
    }

I can write InsertItem(object item) instead and then cast in the method like below:

private void InsertItem(object item)
     {
      this.array[0] = (T)Convert.ChangeType(item, typeof(T));
     }

But this is probably not a good practice. I also need to know the type of argument at client so that I can parse there and then invoke the method. I am new to Generics so help me out here please.

11
  • 3
    Where are you trying to invoke the method? Why do you need to invoke it? InsertItem(5) will compile just fine. T resolves to int. Commented Jul 30, 2013 at 21:24
  • What is the type of this.array? Commented Jul 30, 2013 at 21:25
  • @Amy I am trying to invoke the method from a console app inside main() and I am adding the class to my project. I need to invoke it because this is only way user can insert an item in an array. InsertItem(5) will compile fine but I am reading the user input Console.Readline() so if my InsertItem takes int as its argument type then it would say cannot convert from string to int. Commented Jul 30, 2013 at 21:54
  • @EricLippert this.array is generic array type inside the class I mentioned above private T[] array = new T[0]; You probably figured it but I am trying to build a class that will use only arrays to store undetermined number of items of user defined type. Commented Jul 30, 2013 at 22:00
  • 1
    You might consider obtaining the source code to the base class library -- search for "Microsoft Shared Source Initiative" -- and study how List<T> works. Commented Jul 31, 2013 at 14:28

3 Answers 3

10

You don't know the type in the body of the method. If you knew the type then you would not have used generics in the first place.

You might not want to use generics here. If you need to make a decision based on the type then your method is not generic.

Sign up to request clarification or add additional context in comments.

2 Comments

" If you need to make a decision based on the type then your method is not generic." - classic...
Yes exactly. I don't know the type in the method body I also want user to have the flexibility to initialize any type of array. So, I hope you understand what I am trying to do here. What changes would you suggest then?
0

When you specify the generic parameter as int, you may as well assume that type later on. So your code in the Console application becomes:

static void Main(string[] args)
{
    // Specifying int here ...
    UnlimitedGenericArray<int> oArray = new UnlimitedGenericArray<int>(); 
    while(true)
    {
     string userInput = Console.ReadLine();
     int number = int.Parse(userInput);
     // ... therefore we know that the method below requires an int
     oArray.InsertItem(number);
    }
}

1 Comment

No, sir. Like I mentioned above, user can initialize a UnlimitedGenericArray<string> or UnlimitedGenericArray<decimal> or any type for that matter. There is no room for assumptions I have to know the type at runtime and parse according to that.
0

The only option that comes to mind is to hand the class a method of converting from a known type into in the form of a Type/Func dictionary, like this:

public class UnlimitedGenericArray<T>
{
    public IList<T> List { get; set; }

    private IDictionary<Type,Func<object,T>> InserterFuncDict{get;set;}

    public UnlimitedGenericArray(IDictionary<Type,Func<object,T>> inserterDict)
    {
        this.List = new List<T>();

        this.InserterFuncDict = inserterDict;
    }

    public void AddItem(object item)
    {
        var itemType = item.GetType();
        if(itemType == typeof(T))
        {
            this.List.Add((T)item);
        }
        else if(this.InserterFuncDict.ContainsKey(itemType))
        {
            this.List.Add(this.InserterFuncDict[itemType](item));
        }
        else 
        {
            var msg = "I don't know how to convert the value: {0} of type {1} into type {2}!";
            var formatted = string.Format(msg,item,itemType,typeof(T));
            throw new NotSupportedException(formatted);
        }
    }

}

Then the usage would look like this:

var arr = new UnlimitedGenericArray<int>(new Dictionary<Type,Func<object,int>>()
{
    { typeof(string), v => int.Parse(v.ToString()) }
});

// ok! int == T
arr.AddItem(123); 
// ok, a mapping is provided
arr.AddItem("123"); 
// Error! 
//"I don't know how to convert the value: False of type System.Boolean into type System.Int32!"
arr.AddItem(false);

Then if say, you wanted to add boolean support you could change the declaration to:

var arr = new UnlimitedGenericArray<int>(new Dictionary<Type,Func<object,int>>()
{
    { typeof(string), v => int.Parse(v.ToString()) }
    { typeof(bool), v => bool.Parse(v.ToString()) }
});

Just keep adding to the type convert dictionary as needed.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.