Why should I specify <type> in the <type> () method? And how can you use it?
Considering the application code below, having 3 overloaded extension methods that do the exact same thing as the same input and output:
- What is the use (or difference) of using both call parameters and method definition?
- Why use them (if the same method 3 without them would be called and do the same)?
- And how can they (such information) be manually or explicitly used inside a method?
Code:
namespace LINQ_CreatingYourFirstExtensionMethod
{
internal class Program
{
private static void Main(string[] args)
{
string[] aBunchOfWords = {"One", "Two", "Hello", "World", "Four", "Five"};
var iEnuResult = from s in aBunchOfWords
where s.Length == 5
select s;
iEnuResult.Write();
iEnuResult.Write<string>();
iEnuResult.Write<object>();//same effect as above line
Console.ReadKey();
}
}
}
Overloaded Write () extension methods:
namespace LINQ_CreatingYourFirstExtensionMethod
{
public static class Utils
{
public static void Write(this IEnumerable<object> source) //****1
//public static void Write(this IEnumerable<string> source)//same effects as above line
{
foreach (var item in source)
{
Console.WriteLine(item);
}
}
public static void Write<T>(this IEnumerable<T> source)//****2
{
foreach (var item in source)
{
Console.WriteLine(item);
}
}
public static void Write(this IEnumerable source)//******3
{
foreach (var item in source)
{
Console.WriteLine(item);
}
}
}
}
Update:
Can you give me the simplest illustration why I need
- method call with
<Type>
- define a method with
<Type>
if i can do it all without it?
Update2:
I didn't write this right away, as I thought it was obvious from the context of the question.
In the current code:
- the call
iEnuResult.Write();
goes into the 1st method:
public static void Write (this source is IEnumerable) // ** 1 - iEnuResult.Write (); (or iEnuResult.Write ();) the call
goes into the 2nd method: public static void (this is the IEnumerable source) // * * 2
If you comment
public static void Write1<T>(this IEnumerable<T> source)//*****2
then
iEnuResult.Write1<object>();
cannot be done (only iEnuResult.Write();
)
And if you comment out both the 1st and 2nd methods, the 3rd call is called
iEnuResult.Write();
Thus, it is possible to call the "same" method with <Type>
or without it in the call (call), as well as to define the method with <Type>
and without it.
There are several combinations (I would say dozens) to do seemingly the same things, and I don't see much point in doing this. So, I would like to understand what is the purpose of the existence of such differences, if any
source to share
To focus on your two questions:
- Why call a method with
<Type>
- Why define a method with
<Type>
First, the second question . Let me rephrase it: when do I define a generic method?
You are defining a generic method when the method targets many types, but one type at a time. There are two big benefits:
- Provides type safety (compile time):
IEnumerable<string>
will only contain strings, not an odd integer or whatever. -
This is a way to use types without boxing and unboxing (i.e. converting value types to and from
object
, respectively). As stated here :Boxing and unboxing carry a significant penalty rate, but it also increases pressure on the managed heap, resulting in more garbage collections, which is not good for performance.
If you only have an untyped method (3), each row is squared when untyped IEnumerable
( IEnumerator.Current
returns object
) and unboxed again to call the method ToString()
on the particular type. And the original list can contain anything (which doesn't matter here, but often does).
The general method (2) skips boxing and unboxing and is type safe.
The first method causes any input parameter to be converted (either explicitly or implicitly) to IEnumerable<object>
. Again, boxing and unboxing will occur. But another annoying thing is that there will not always be an implicit conversion available, which forces the consumer of the method to do the conversion explicitly before calling it. The effect of this can be illustrated by changing select s
to select s.Length
. If only method 1 is available, you will receive
Instance argument: cannot be converted from
'System.Collections.Generic.IEnumerable<int>'
to'System.Collections.Generic.IEnumerable<object>'
I think the general rule of thumb is to avoid method parameters like object
(or IEnumerable<object>
, etc.) unless there is another option.
In short: your second method is the best option here because it does the job for any type, but avoids boxing and unboxing.
Now your first question . When do you need to specify a generic type parameter in method calls? I can think of three reasons (maybe more):
- If there is no type method parameter
T
by which the compiler can infer the generic type. Factory are usually found in this category. A method like thisT Create<T>()
should be called, for exampleCreate<Customer>()
. Constructors are another example: generator constructors cannot even be called without the specified type. - If you want to enforce a specific method overload. This can happen when there are inherited types with a mixture of generic and non-generic overloading methods. (By the way, this is not a sign of good design.)
- Indirectly when the type is not known at compile time, but only at run time. See Generics in C # using variable type as parameter .
source to share