C Generic Parameter Conversion

  • 2021-12-04 19:28:16
  • OfStack

The objects generated by different parameter types of generics are independent of each other.


// Such as 
Tuple<string> ts;
Tuple<object> to;
//ts to  Are two types of objects. 

Many times, we want to implement to = ts. Why? Because it seems that it should be.

To achieve this goal, we need to solve the "generic parameter conversion problem", and the knowledge point of this problem is in out generic variant. To be honest, the problem itself is not difficult, but it is very intuitive and easy to forget.

First of all, in order to implement to = ts, there is actually a premise, that is, this parameter can only be used on "return type".


// Such as 
delegate object FuncObj();
FuncObj func = ()=>"string";

func is successful because string can be converted into object. When the "user" calls func, he wants an object object, and string is also an object object, so there is no problem.

The key here is to learn to analyze problems from the perspective of "users".


//A
delegate void FuncObj2(object obj);
FuncObj2 func2 = (string str)=>{};
//B
delegate void FuncStr(string str);
FuncStr func3 = (object obj)=>{};

Analyze these two sets of codes, which one is more reasonable?

From the user's point of view, it uses func2 and func3

When the user uses func2, the object passed must be object, but the actual function processed is (string) = > {}, object cannot be converted to string, so it is very unreasonable.

When the user uses func3, the object passed can only be string, and the actual function processed is (object) = > {}, string can be converted to object, so it is reasonable.

Of course, these two sets of codes are not valid because the function parameter types do not match.

However, generics provide a method to implicitly convert objects with mismatched types! The logic of its implementation is analyzed above.


//out  Modify return type 
delegate ResultType FuncOut<out ResultType>();
//in  Modify parameter type 
delegate void FuncIn<in ParamType>(ParamType param);
// This is 1 Start what we want to achieve 
FuncOut<object> fun4 = () => "string";
// This effect is just the opposite 
FuncIn<object> funcobj = (object obj) => { };
FuncIn<string> fun5 = funcobj;
// Note that generic variants 1 You can only implicitly convert between generic variants and generic variants 
//lambda Expressions are automatically converted to generic variants with the same parameters, but implicit conversion between variants cannot be followed, so you need to funcobj To transition 

out modifies the return type and in modifies the parameter type, which is quite vivid, but note that the generic in parameter is the opposite of the out parameter.

At first, we wanted to implement to = ts, but we only saw the first half of the problem. In fact, generics have the possibility of ts = to. I hope readers can understand this point.

Summary:

out : to = ts;

in : ts = to;

No modification: to and ts are completely independent.

----(Remarks)------------------------------------------------------------------------------------------------------------------
out parameter: Can only be used with return types.

in Parameter: Can only be used on parameters.

Undecorated: Anywhere.

-----(Note 2)----------

in, out generic parameters can only be used on delegates and interfaces.


// Comprehensive application 
delegate ResultType FuncInOut<in ParamType, out ResultType>(ParamType param);
FuncInOut<object, string> funcobj2 = (object obj) => "string";  
FuncInOut<string, object> func6 = funcobj2;

Related articles: