C# - Need Help Understanding the Lambda Operation and <T> [closed] - c#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I'm currently working on a project, and need a method to get me a variable's name. (XmlNode type). I found this solution - but I have no clue how it works. Any explanation would be helpful. Thank you!
static void Main(string[] args)
{
GetName(new { var1 });
GetName2(() => var1);
}
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
static string GetName2<T>(Expression<Func<T>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
In particular, I don't understand why the parameter is (new {var1}) and (() => var1) when calling the methods, what <T>(T item) where T : class means, and what <T>(Expression<Func<T>> expr) means.
I did read about the lambda operation and <T>, but that doesn't really help that much.

First, the nameof operator was introduced in, I believe, c# 6. It can do what you want. You use it like this:
var myVariable = new Object();
var myVariableName = nameof(myVariable);
Now to unpack your question.
What is (new {var1})?
Here you are calling the GetName method. That method takes a single parameter. The object being passed to the method in this case is instantiated with this code: new { var1 }. Here new { var1 } is creating an anonymous type. The object being created has a single property named 'var1' whose value is the variable var1. Because a property name was not supplied the property was automatically given the same name as the variable. You could have explicitly named the property when you declared the anonymous type like this: new { var1 = var1 }. Or you could have given your property a completely different name: new { DifferentName = var1 } (but this would cause GetName to return the wrong result - see below). If you were to explicitly define these types as classes they would look something like these, respectively:
public class MyClass<T>
{
public MyClass(T property)
{
var1 = property;
}
public var1 { get; }
}
and this:
public class MyClass<T>
{
public MyClass(T property)
{
DifferentName = property;
}
public DifferentName { get; }
}
What is <T>(T item) where T : class?
The <T> in GetName<T> or GetName2<T> is a generic type parameter (generics). In this case it allows you to delay the type specification of the method parameter until the method is invoked. So if I had a method with this signature, for example, MyMethod<T>(T item) I could later call it with an int like this MyMethod<int>(2) or a string like this MyMethod<string>('some string'). Here I am explicitly specifying the type with <int> and <string>. In many cases, when the type is unambigous, you can exclude the type declaration and C# will infer it. So I could do this MyMethod('some string') and C# will be able to infer the type is string. That is what is happening here: GetName(new { var1 }). Since new { var1 } is an anonymous type there is no way to explicitly specify the type when calling GetName. But you can still call GetName with an anonymous type simply by allowing C# to infer the type.
The where T : class portion of the method signature is just a generic constraint, i.e. a constraint is being placed on the types that can be passed to this method. In this case the constraint is that T must be a class and not a value type.
How does GetName<T> work?
This function is using reflection to inspect the object that was passed to it. Here is what is going on: typeof(T) gets the type of object that was passed (remember we are passing an anonymous type), GetProperties() gets all the properties of the type - this will give you an array of PropertyInfo, [0] gives you the first property in that array (in the case where new { var1 } is passed to this method the object will only have a single property named 'var1'), and finally Name gives you the name of that property.
This method is making assumptions about the object being passed to it. Specifically that the object passed has at least 1 property and that the name of the the first property has the same name as the variable whose name we are interested in. This method is far from foolproof, it could easily be broken at runtime by passing an object with no properties, or you could get back the wrong name if you failed to pass an object that conformed to the assumptions that GetName is making.
Interestingly, GetName could have been implemented without generics like this:
static string GetName3(object item)
{
return item.GetType().GetProperties()[0].Name;
}
Perhaps the author was attempting to take advantage of at least a tiny bit of compile time checking by eliminating an entire class of objects (value types) that have no properties from being passed to the method.
What is (() => var1)?
This is an expression. This particular expression represents a function that takes no parameters () and returns an object. I know that from the method signature of GetName2:
GetName2<T>(Expression<Func<T>> expr)`
See, the expr parameter is an Expression of type Func (a function) that takes no parameters and returns a on object of type T.
How does GetName2<T>(Expression<Func<T>> expr) work?
Well... the short and probably not very accurate answer is that it is returning the right side of the expression. So you pass in () => var1 and you get back var1. Let's just leave it at that for now.

new {var1} creates an anonymous object
(() => var1) is a lambda function with no parameters shorthand for:
delegate void () { return var1;}
<T>(T item) where T : class is reflection and constraining the generic
parameter to a class. See DarkSquirrel42 answer

Related

Why can't I convert from 'out BaseClass' to 'out DerivedClass'?

I just learned that having a generic argument as the type of an out parameter forces that generic type to be invariant. This is surprising to me. I thought out parameters are treated the same as return types (i.e. if the generic parameter is covariant, then it can be used in as an out out parameter), since they are both "outputs" of a method.
After a bit of investigation, I realised that you can't do this:
public class Program {
public static void Main() {
// cannot convert from 'out object' to 'out string'
F(out object s); // passing an out object
}
public static void F(out string o) {
o = null;
}
}
This explains why out parameters must be invariant. However, I still don't understand why you can't do this. As is commonly known, out parameters are just another way of returning a value. F could be rewritten with a return value, and it will work:
// This is the semantically equivalent version of the above, just without "out"
public class Program {
public static void Main() {
object s = F();
}
public static string F() {
return null;
}
}
So why doesn't the first code snippet compile? Does using out allow F to do something that can't be done with return values, that will break type-safety if an out object s were passed to it?
I found this question, which is about converting the other way - from a derived class to a base class, which clearly isn't possible. You can't assign the return value of a method that returns a object to a variable of type string, can you?
What I'm asking is, since you can assign the return value of a method that returns string to a variable of type object, why can't you do the same with out parameters? That is, why can't you pass an out object to a out string parameter?
I also read the docs and the spec, but they never mentioned anything about the fact that you have to pass the exact same type into a out parameter, let alone explain why you have to do it.
With out parameters the argument is passed by reference just like ref, the difference is that the value must be assigned by the end of the method and the reference does not need to be initialized before calling. But it can be initialized before and the method can read the initial value.
From the docs: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier
The out keyword causes arguments to be passed by reference
It is like the ref keyword, except that ref requires that the variable be initialized before it is passed
As the method can read the variable, the reference must be of type string to work. The reading blocks covariance and the output blocks contravariance, thus the argument must be invariant.
As is commonly known, out parameters are just another way of returning a value
Not true: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out
As a parameter modifier, which lets you pass an argument to a method by reference rather than by value.
That means that you are passing on a reference to a specific object.
I think your answer though is here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref
Passing a reference type by reference enables the called method to replace the object to which the reference parameter refers in the caller.
So when you are passing an object to the function you are effectively doing an assignment of type
derived <- base
and when you are assigning from inside the function
base <- derived
Think about that you can do something like this in c#:
public static void Out(out string s)
{
Thread.Sleep(50);
s = "World";
}
public static void Ref(ref string s)
{
Console.WriteLine(s); // Hello
Thread.Sleep(100);
Console.WriteLine(s); // World
}
string str = "Hello";
new Thread(() => Out(out str)).Start();
new Thread(() => Ref(ref str)).Start();
If it is legal to change string str to object str, now str can be any type, how to keep the reference between Out and Ref method?

What does these generic parameter constraints mean?

I'm using a method with this as the 1st parameter:
Action<IFieldsetter<Contact>>
How do I read this? Does is mean that this must be an Action object where the Action constructor is constrained to accept only something that implements IFieldsetter? And it looks like IFieldsetter itself is being constrained, but I don't understand this part at all.
It's not an actual constraint, but just the type it needs. So, that method's first parameter is an Action (i.e. delegate), which has only one parameter, and that parameter is a IFieldsetter<Contact>, whatever that means. My guess is that IFieldsetter exposes a setter and in this case it must handle the type Contact, but you should be the one who knows for real what they are and do! Post the code of this interface and this class if you need further help.
For example, if it was Action<IEnumerable<String>>, it would mean that the delegate receives a list of strings as a parameter. Here's some code:
// Your method with the *special* parameter.
private void ChrisMethod(Action<IEnumerable<String>> method)
{
string[] exampleList = { "First", "Second", "Third" };
method(exampleList);
}
// The method that can be used as parameter.
private void ParameterMethod(IEnumerable<String> list)
{
foreach(string str in list)
Console.WriteLine(str);
}
public void Main()
{
ChrisMethod(ParameterMethod);
}
A constraint on a type parameter is a different thing. You can learn more about that here.
A C# System.Action (MSDN) is a delegate object where Action<T> is the equivalent of a delegate function matching void FunctionName(T). So you can set it to a function and later on call that function.
The section generics block <Contact> applies to the IFieldsetter, so you have an Action that takes an argument of IFieldsetter<Contact>. Without knowing anything about the IFieldsetter I can't tell you what it's going to do with the Contact generic argument there.
In order to use this, you'll can have something resembling the following:
void Main()
{
FunctionThatDoesStuff(SetField);
}
void FunctionThatDoesStuff(Action<IFieldsetter<Contact>> action)
{
var setter = new IFieldsetter<Contact>();
action(setter);
}
void SetField(IFieldsetter<Contact> setter)
{
}
This is nested generic type parameter. From the outermost layer, you can see that this is an Action<T> delegate. And the delegate needs an argument of type T. In this case, T is replaced by IFieldsetter<Contact>. i.e. Action<IFieldSetter<Contact>> needs an argument of type IFieldSetter<Contact>. Now the IFieldSetter<T> interface sets a field of type T. And in this case, T is replaced by Contact so IFieldSetter<Contact> sets a field of type Contact.
Let's sum up: Action<IFieldsetter<Contact>> represents an Action delegate that needs an argument of type IFieldSetter which can set a field of type Contact. Now do you understand?
Action<IFieldsetter<Contact>> means Action delegate accepts a parameter of type that implements a generic interface IFieldsetter. suppose a class is implemented with IFieldsetter intercae with Contact as the generic parameter as shown below.
public class Test: IFieldsetter<Conatct>
{
}
Now instance of this test class can be passed as parameter to the Action deletegate.

Dynamically pass class and method names to a method using generics

I want to pass in dynamically a class name and a method name to a method and keep this dynamic, I'm understanding that I should use generics and possible constraints.
Example, I have a class
MemberRequestDTO (contains several properties)
I also that a Method called
RecordsToRetrieve
Using some reflection I was wanting to dynamically get the values of the properties, which I figured out how to do that, but then I realized that is is too hard code and tightly coupled of which I figured time to refactor and create a method with a signature that uses generics with constraints. having trouble with understand the use of and the constraints etc..
So I want to pass in a class name and be able to use it in the method, with reflection I plan to use it like:
Type type = typeof(classname);
I started reading and researching and I start playing with code like this:
public void GetTypeValues<T>() where T : class , new()
How do I pass in the class name of MemberRequestDTO?
What does the Generic new for me?
How do I pass a class name into the parens ()?
If I use does it also get pass into parens?
How can I pass in class and method?
Reading the above "Where T has the constraints (enforced) to be of type "class AND new() ?
A little lost and confused on this, forgive me.
EDIT:
Based on the answers and some research, I'm understanding this a bit more:
Lets forget about me trying to pass in a method, say I just want to pass in a class
Say the class with properties looks like this
public class MemberRequestDTO
{
public DateTime DateRequested { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then I will New this up
var memberRequestDTO = new MemberRequestDTO();
Then I want to pass this to class into a method that is generic
How do I go about passing an instance of a object into a generic method? What about the signature , example public void GetTypeValues() where T : class , new()
Would I want to have the contraints of class and new() ?
For the above, is T the instance of the class? Thus the purpose is that I can be
Saying
GetTypeValues(memberRequestDTO)
( this is my actual question , pass into whatever class I instantiated and that let the method "handle" dealing with that class with looping through the properties and getting me the name values of the properties dynamically and yes it probably will not remain a void method )
Should passing in memberRequestDTO be with quotes or without? I want to be able to pass in any instance of a class to the member to then manipulate it more. () should T be there ? should the parens () be empty or contain an generic parameter for the class object ?
Here are your answers:
GetTypeValues<MemberRequestDTO>()
new() is a constraint for the Type Parameter - T. It says that the type argument T must have a public parameterless constructor. In your case, MemberRequestDTO class must a public parameterless constructor like below:
public class MemberRequestDTO
{
public MemberRequestDTO() { ... }
}
As a class name is of reference type, you can pass it as a type into the parens like: SomeMethod(typeof(MemberRequestDTO)); where the signature of the method be void SomeMethod(Type type) { }
If you pass the class as a type parameter as in point (1), it does not get passed into the parens()
class constraint implies that "The type argument must be a reference type; this applies also to any class, interface, delegate, or array type."
and new() constraint implies that "The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last."
EDIT:
If I catch your point, then the generic method definition would be something like:
public void GetTypeValues<T>(T typeObject) where T : class
{
// typeObject specific operations
}
That uses typeObject dynamically, getting the "execution-time compiler" to perform type inference to work out T. See the reference here. Moreover, imho, you don't need the new () constraint on T here.
After that, you can pass an instance of any class to this method like below:
var memberRequestDTO = new MemberRequestDTO();
GetTypeValues((dynamic) memberRequestDTO);
EDIT 2:
USAGE: Get Type Values dynamically using Reflection
This method returns the property values wrapping into IEnumerable<KeyValuePair<string, object>>.
public static IEnumerable<KeyValuePair<string, object>> GetTypeValues<T>(T typeObject) where T : class
{
// typeObject specific operations
IEnumerable<KeyValuePair<string, object>> typeValues =
typeObject
.GetType()
.GetProperties()
.Select(property => new KeyValuePair<string, object>(property.Name, property.GetValue(typeObject)));
return typeValues;
}
How do I pass in the class name of MemberRequestDTO ?
You already have one. In a generic method "Type parameter" in this case T will be the name of type you're interested in.
public void GetTypeValues<T>() where T : class , new()
{
string typeName = typeof(T).Name;
}
What does the Generic new for me?
It is a contraint which will prevent you to pass any type without public parameterless constructor. In other words it will allow you to new up type passed in as "Type parameter"
public void GetTypeValues<T>() where T : class , new()
{
T instance = new T();//This is not possible without new constraint
}
How do I pass a class name into the parens () ?
If I use does it also get pass into parens?
Not sure what is that parens() Need more info to answer this.
How can I pass in class and method?
If I understand correctly "Type parameter" T is the runtime type which you use. So you get a Type there. Am not sure about what you mean by class? Class cannot be passed only instances can be passed.
For methods there are number of ways. You can pass MethodInfo or method name or A delegate, or a MethodCallExpression etc.
Reading the above "Where T has the constraints (enforced) to be of
type "class AND new() ?
Yes. class constraint prevents you from passing value types, new() constraint allows you to new up things.
Read more about generics here and here
I'm a little confused about what you want to do but I'll give it a shot. I can see two possible interpretations and they differ on what the caller is starting with and what you're trying to achieve.
Interpretation #1: The caller starts out knowing the name of the class and the name of the method it wants to invoke later, using an object it has in hand. This can be achieved as follows:
public Func<object, object> RecordMethod(string typeName, string methodName)
{
var type = Type.GetType(typeName);
var method = type.GetMethod(methodName);
return (object o) => method.Invoke(o, new object[0]);
}
var method = RecordMethod("MemberRequestDTO", "RecordsToRetrieve");
// later that day ...
MemberRequestDTO someObj = ...;
var result = method.Invoke(someObj);
This is fine if you need to work with type names and method names dynamically, e.g. from user input. Note that this approach requires the use of object throughout, and will only work with a method that takes no parameters. Also note that in this way the type cannot be guaranteed to have a no-arg constructor, so the caller must provide the object himself.
Interpretation #2: The caller starts out knowing the actual class and the actual method it wants to invoke later, using an object that can be constructed later. This can be achieved as follows:
public Func<TOutput> CaptureMethod<TInput, TOutput>(Func<TInput, TOutput> method)
where TInput : new()
{
return () =>
{
var source = new TInput();
return method(source);
};
}
var capturedMethod = (MemberRequestDTO dto) => dto.RecordsToRetrieve();
// later that day ...
var result = capturedMethod();
This captures a known method and returns a function which, when invoked, will instantiate your class and call the method on it. This is a more static approach (the caller knows more than in the previous example) and is able to enforce a constraint that the type being worked with must have a no-arg constructor.
I don't know if I've answered your question but this should at least give you some ideas.

.Net lambda expression-- where did this parameter come from?

I'm a lambda newbie, so if I'm missing vital information in my description please tell me. I'll keep the example as simple as possible.
I'm going over someone else's code and they have one class inheriting from another. Here's the derived class first, along with the lambda expression I'm having trouble understanding:
class SampleViewModel : ViewModelBase
{
private ICustomerStorage storage = ModelFactory<ICustomerStorage>.Create();
public ICustomer CurrentCustomer
{
get { return (ICustomer)GetValue(CurrentCustomerProperty); }
set { SetValue(CurrentCustomerProperty, value); }
}
private int quantitySaved;
public int QuantitySaved
{
get { return quantitySaved; }
set
{
if (quantitySaved != value)
{
quantitySaved = value;
NotifyPropertyChanged(p => QuantitySaved); //where does 'p' come from?
}
}
}
public static readonly DependencyProperty CurrentCustomerProperty;
static SampleViewModel()
{
CurrentCustomerProperty = DependencyProperty.Register("CurrentCustomer", typeof(ICustomer),
typeof(SampleViewModel), new UIPropertyMetadata(ModelFactory<ICustomer>.Create()));
}
//more method definitions follow..
Note the call to NotifyPropertyChanged(p => QuantitySaved) bit above. I don't understand where the "p" is coming from.
Here's the base class:
public abstract class ViewModelBase : DependencyObject, INotifyPropertyChanged, IXtremeMvvmViewModel
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged<T>(Expression<Func<ViewModelBase, T>> property)
{
MvvmHelper.NotifyPropertyChanged(property, PropertyChanged);
}
}
There's a lot in there that's not germane to the question I'm sure, but I wanted to err on the side of inclusiveness.
The problem is, I don't understand where the 'p' parameter is coming from, and how the compiler knows to (evidently?) fill in a type value of ViewModelBase from thin air?
For fun I changed the code from 'p' to 'this', since SampleViewModel inherits from ViewModelBase, but I was met with a series of compiler errors, the first one of which statedInvalid expression term '=>' This confused me a bit since I thought that would work.
Can anyone explain what's happening here?
where does 'p' come from in
NotifyPropertyChanged(p => QuantitySaved);
The lambda is being passed to a method called NotifyPropertyChanged. There is one overload of that method. It has formal parameter type Expression<Func<ViewModelBase, T>>. That is, the formal parameter expects to get a lambda that takes a ViewModelBase and returns a T, for some T.
The p is the parameter that the lambda takes.
The compiler is able to infer that the author of the code neglected to spell out the type of the lambda parameter explicitly. The author could also have written:
NotifyPropertyChanged((ViewModelBase p) => QuantitySaved);
had they wanted to be explicit about it.
how does the compiler know to fill in a type value of ViewModelBase from thin air?
The compiler examines all possible overloads of NotifyPropertyChanged that could possibly take a lambda in that argument position. It infers the formal parameter type of the lambda from the delegate types that are in the formal parameter types of the NotifyPropertyChanged methods. An example might help. Suppose we have:
void M(Func<int, double> f) {}
void M(Func<string, int> f) {}
and a call
M(x=>x.Length);
The compiler must infer the type of the lambda parameter x. What are the possibilities? There are two overloads of M. Both take a delegate in the formal parameter of M corresponding to the first argument passed in the call. In the first one, the function is from int to double, so x could be of type int. In the second one, the formal parameter of M is a function from string to int, so x could be string.
The compiler must now determine which one is correct. In order for the first one to be correct, the body of the lambda must return a double. But if x is int, there is no property Length on x that returns a double. So x cannot be int. Can x be string? Yes. There is a property Length on x that returns an int if x is string.
Therefore the compiler deduces that x is string.
These deductions can get extraoridinarily complicated. A slightly more complicated example:
void M<A, B, C>(A a1, Func<List<A>, B> a2, Func<B, C> a3) {}
...
M(123, x=>x.Count.ToString(), y=>y.Length);
Type inference must infer the types A, B, C and therefore the types of x and y. The compiler first infers that A must be int since a1 is 123. It then infers that x must be List<int> from that fact. It then infers that B must be string, and therefore y is string, and therefore C is the type of y.Length, which is int.
It gets a lot more complicated from there, believe me.
If this subject interests you, I have written a number of articles and filmed some videos on the subject of various kinds of type inference performed by the compiler. See
http://blogs.msdn.com/b/ericlippert/archive/tags/type+inference/
for all the details.
For fun I changed the code from 'p' to 'this', since SampleViewModel inherits from ViewModelBase, but I was met with a series of compiler errors, the first one of which statedInvalid expression term '=>' This confused me a bit since I thought that would work.
The only acceptable left-hand-side of a lambda operator is a lambda parameter list; "this" is never a legal lambda parameter list. The compiler is expecting "this" to be followed by ".SomeMethod()" or some such thing; the compiler assumes that "this" will never be followed by "=>". When you violate that assumption, bad things happen.
p is just a dummy name, it's the name of the parameter like in any method. You could name it x or Fred, if you like.
Remember, lambda expressions are just very, very special anonymous methods.
In regular methods you have parameters, and they have names:
public double GetQuantitysaved(ViewModelBase p) {
return QuantitySaved;
}
In anonymous methods you have parameters, and they have names:
delegate(ViewModelBase p) { return QuantitySaved; }
In lambda expressions you have parameters, and they have names:
p => QuantitySaved
The p here plays the same role in all three versions. You can name it whatever you want. It's just the name of a parameter to the method.
In the last case, the compiler does a lot of work to figure out that p represents a parameter of type ViewModelBase so that p => QuantitySaved can play the role of
Expression<Func<ViewModelBase, T>> property
For fun I changed the code from p to this, since SampleViewModel inherits from ViewModelBase, but I was met with a series of compiler errors, the first one of which stated Invalid expression term '=>' This confused me a bit since I thought that would work.
Well, this is not a valid parameter name because it's a reserved keyword. It's best to think of p => QuantitySaved as
delegate(ViewModelBase p) { return QuantitySaved; }
until you get comfortable with the idea. In this case, this could never be substituted in for p as it is not a valid parameter name.
The lambda p => QuantitySaved is an expression of type Expression<Func<ViewModelBase, int>>. Since the method NotifyPropertyChanged is looking for an expression of <ViewModelBase, T>, it fits.
So the compiler is able to infer that p is a ViewModelBase. p didn't "come from" anywhere, it's basically being declared right here. It's a parameter for the lambda. It's going to be filled in when someone uses the property parameter of your method. For example, if you put your lambda into a separate variable called lambda, you could call it with lambda(this) and it would return the QuantitySaved value.
The reason you can't use this in the lambda is because it's expecting a parameter name, and this isn't a valid name. The point is that you could call it on any instance of ViewModelBase, not just the one that created the lambda.
The easy way to understand this is to replace this:
p => QuantitySaved // lambda
with this:
delegate (ViewModelBase p) { return QuantitySaved; } // anonymous delegate
Which is effectively the same. p is a parameter name for first parameter of your anonymous delegate. You can give it any name appropriate for parameter names (this is a keyword, you cannot use it as parameter name)
In this particular example this p variable is redundant by the way, you could use parameterless delegate as well.
From the NotifyPropertyChanged signature:
void NotifyPropertyChanged<T>(Expression<Func<ViewModelBase, T>> property)
The method expects an expression that takes an input of type ViewModelBase and returns an instance of type T.
The p parameter is an instance of ViewModelBase.

What are the advantages of using generics in method signatures?

(Thanks everyone for the answers, here is my refactored example, in turn another StackOverflow question about the Single Responsibility Principle.)
Coming from PHP to C#, this syntax was intimidating:
container.RegisterType<Customer>("customer1");
until I realized it expresses the same thing as:
container.RegisterType(typeof(Customer), "customer1");
as I demonstrate in the code below.
So is there some reason why generics is used here (e.g. throughout Unity and most C# IoC containers) other than it just being a cleaner syntax, i.e. you don't need the typeof() when sending the type?
using System;
namespace TestGenericParameter
{
class Program
{
static void Main(string[] args)
{
Container container = new Container();
container.RegisterType<Customer>("test");
container.RegisterType(typeof(Customer), "test");
Console.ReadLine();
}
}
public class Container
{
public void RegisterType<T>(string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", typeof(T), dummy, typeof(T).Name);
}
public void RegisterType(Type T, string dummy)
{
Console.WriteLine("Type={0}, dummy={1}, name of class={2}", T, dummy, T.Name);
}
}
public class Customer {}
}
//OUTPUT:
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
//Type=TestGenericParameter.Customer, dummy=test, name of class=Customer
One reason when generics are very useful is when the generic type parameter is used as the type of a parameter or as the return type of the method.
That means, you can write methods like
public T GetAs<T>(string name)
where the return type can be checked by the compiler and boxing value types can sometimes be avoided.
The caller would write:
int value = GetAs<int>("foo");
Whithout generics, you would have to write
public object GetAs(Type t, string name)
and the caller has to cast the result again:
int value = (int)GetAs(typeof(int), "foo");
A primary reason is the type safety at compile time. If you are passing two Type objects you are placing the responsibility at the developer instead of the compiler.
This is also why many IoC containers utilizes it, as your compiler will complain if an concrete type isn't inheriting the abstract type.
public void Register<TAbstract, TConcrete>() where TConcrete : TAbstract
{
}
This code will only work if TConcrete is implementing or inheriting TAbstract. If this method took two Type parameters, your method should validate this relationship.
A simple answer is type inference where possible.
If the generic type is used in the method signature, you can omit it because the type could be inferred:
void SomeMethod<T>(T x, T y) where T : IComparable<T> {
Console.WriteLine("Result: {0} to {1} is {2}", x, y, x.CompareTo(y));
}
So the usage is simplified:
SomeMethod(3, 4); // instead of SomeMethod<int>(3, 4);
SomeMethod("one", "two"); // instead of SomeMethod<string>("one", "two");
If the generic type parameter is not used in the method signature the type inference is not possible:
var emptySequence = Enumerable.Empty<int>();
I think one of the primary uses is type safety with arguments and return values. In your example case, there is not much use for generics, because the input/output types (string) do not match the generic case (customers).
A more appropriate use might be:
public T RegisterType<T>(string name)
{
T obj = new T();
obj.DoSomething();
return obj;
}
or maybe
public void DoSomething<T>(T obj)
{
//operate on obj
}
If you didn't use Generics, you'd either have to overload a method for each type you want to support, or you'd have to accept the parameter as an object and perform casting logic.
For one example, compare the code needed to create an instance of your type using the typeof option versus a generic. Or return an instance of the type. Or accept an instance of the type as an argument. Or set a property on an instance of the type.
In general, if you will be working only with the type itself you can accept a type parameter. If you want to do anything with an instance of the type, use a generic.
Another reason to use a generic is if you want to apply constraints to the type. For example, you can require the type to implement one or several interfaces, inherit another type, be a reference type or value type, have a default constructor, or some combination of the above. The compiler will enforce this so you can't build code that doesn't comply with your requirements.
I'd say the best reason is type safety, using the "where" keyword, to ensure that the generic type is of a certain type (or sub-class/implementor). Using "typeof" will let you send anything through.

Categories

Resources