For type safety and box avoidance, the only option is to specifically overload the input type int :
public void AttachInput(int input) { Inputs.Add(input); }
Update:
The OP updated the question using theory:
Taking a deeper look at generics, it seems to me that Convert.ToInt32, when T is already an int, does not box for an object and its int overload is one of which is called.
This is wrong, and a simple test can demonstrate it. Suppose we write our own set of overloads only to determine which one is being called:
public static class OverloadTest { public static void Foo(int x) { Console.WriteLine("Foo(int)"); } public static void Foo(bool x) { Console.WriteLine("Foo(bool)"); } public static void Foo(object x) { Console.WriteLine("Foo(object)"); } }
Now we will write a general method for modeling what is asked in the question:
static void CallTheRightFoo<T>(T value) where T : struct { OverloadTest.Foo(value); }
The theory is that since the CLR / JIT will create a specific version of the method for each type of value, it can choose a specific overload for int as it becomes available.
So here is the test:
struct Test { } // in order to test a user-defined value type static void Main(string[] args) { CallTheRightFoo(1); CallTheRightFoo(true); CallTheRightFoo(new Test()); }
Output:
Foo(object) Foo(object) Foo(object)
To associate this with Convert.ToInt32 , from your shared code you will always call the overload that takes object , and so the value will be put in a box and then should be unpacked inside Convert.ToInt32 (which should also check what type it is first).
While repeating the important point behind all of this: while boxing / unpacking is more expensive compared to not doing it, it is quite likely to be worth little compared to any real work your code does. Therefore, I would not worry too much about the cost of this until you can prove that this is a genuine burden on a realistic model of an application using your library.
Daniel Earwicker
source share