Pass generic type parameter to Func - c#

I have a couple of function like CallMyFunction in my codebase. I would like to refactor them into one generic function
enum MyEnum
{
ValueA,
ValueB,
ValueC
}
static void MyFunction<T>()
{
//...
}
static void CallMyFunction(MyEnum myEnum)
{
switch (myEnum)
{
case MyEnum.ValueA:
MyFunction<A>();
break;
case MyEnum.ValueB:
MyFunction<B>();
break;
case MyEnum.ValueC:
MyFunction<C>();
break;
}
}
I would like to be able to have something like
//I would like to make it work for Func<T> too
static void GenericCall(MyEnum myEnum, Action<?????> myFunc)
{
switch (myEnum)
{
case MyEnum.ValueA:
myFunc<A>();
break;
case MyEnum.ValueB:
myFunc<B>();
break;
case MyEnum.ValueC:
myFunc<C>();
break;
}
}
//And then call it like this
GenericCall(myEnum, MyFunction);
GenericCall(myEnum, AnotherFunction);

I would simply create a dictionary of myenum/action pairs
Your dictionary:
Dictionary<MyEnum,Action> actions = new Dictionary<MyEnum,Action>()
{
{ValueA, ()=>{your code...}},
{ValueB, ()=>{your code...}}
};
calling a method
static void CallMyFunction(MyEnum myEnum)
{
actions[myEnum]();
}

In your example, there are no parameters for any calls to MyFunction<>, meaning there are no generic arguments required for Action. Likewise, you cannot change to CallMyFunction<T> as T changes depending on the enum.
As for <A>, <B> and <C>, these have to be specified in each case rather than put in as part of a generic argument to Action. The switch is calling the methods, not the caller of GenericCall. It's this key point that you're working around, to dynamically select <A>, <B> and <C> based on the enum value.
Trying to put an argument into CallMyFunction for myFunc effectively means the caller has to supply the types A, B and C which negates the purpose of the switch. This isn't what you're trying to do I think.
One way of refactoring would be to change the method MyFunction<T> to take the type parameter as a parameter rather than a generic. This would allow you to do the following;
enum MyEnum
{
ValueA,
ValueB,
ValueC
}
static void MyFunction(Type type)
{
//...
}
static void CallMyFunction(MyEnum myEnum)
{
Type type;
switch (myEnum)
{
case MyEnum.ValueA:
type = typeof(A);
break;
case MyEnum.ValueB:
type = typeof(B);
break;
case MyEnum.ValueC:
type = typeof(C);
break;
}
MyFunction(type);
}
However this doesn't really save you anything.
To get proper value out of it, you could create a custom Attribute that took a constructor argument of Type and apply the Attribute directly to the enum. Your function MyFunction, could be modified to check for the Attribute on the enum and correctly pass the correct type to MyFunction.
That said, it'd only be worth it if you had a large (>10) enum values/types. The structure as it stands is fairly straight forward and easy (if mundane), to maintain.
It's worth mentioning that you could also use reflection to call MyFunction<> and supply the generic argument at runtime but you'd still be left with picking out the type by enum. It would add more code to maintain rather than reduce it.

Related

Generic method argument <T> detected as a variable

I am currently writing code for runtime post-processing management.
I would like to make a generic method to be more effective but I get 2 error messages:
CS0118: 'procType' is a variable but used like a type (at out parameter)
CS0119: 'Fog' is a type, which is not valid in the given context (when calling the method)
void SetPostProc<T>(T procType, string IOHID, bool defval) where T : VolumeComponent
{
byte value = Convert.ToByte(IOHandler.GetVal(IOHID, defval));
volumeProfile.TryGet(out procType EFX);
{
};
}
SetPostProc(Fog, "", false);
What am I doing wrong?
Thanks for your help in advance!
First of all, if Fog is really a type, and not a variable, then you're not using the proper way of calling the generic function. If the generic type is not obvious from the first parameter, then you have to explicitly specify it like this:
Fog myFogObject = ...;
SetPostProc<Fog>(myFogObject , "", false);
However, if the type of myFogObject is known at compile time, which it seems like it is in your case, you don't have to specify the generic type because the compiler will figure it out automatically:
Fog myFogObject = ...;
SetPostProc(myFogObject , "", false);
This should solve your second error (CS0119).
The second problem is that procType is a variable referring to an object of type T, and not a type. You have to call the TryGet function by passing in the generic type parameter T like this:
volumeProfile.TryGet<T>(out T EFX);
Depending on what you're trying to do with this code, I think you don't even need the T procType parameter, just having the T generic parameter should be enough:
void SetPostProc<T>(string IOHID, bool defval) where T : VolumeComponent
{
byte value = Convert.ToByte(IOHandler.GetVal(IOHID, defval));
volumeProfile.TryGet(out T EFX);
{
// ...
};
}
EDIT: If you still want to get the result of TryGet outside the SetPostProc function, you'll need to declare the first parameter of your function as an out parameter:
void SetPostProc<T>(out T procObj, string IOHID, bool defval) where T : VolumeComponent
{
byte value = Convert.ToByte(IOHandler.GetVal(IOHID, defval));
volumeProfile.TryGet(out procObj);
{
// ...
};
}

How can I pass delegates to a function for generic delegates?

I have a function to return relevant text from various windows controls.
I was hoping to be able to create something a little more elegant, and less static.
Here's code that functions the way I want it to:
public string returnText(Control controller)
{
string bob = controller.GetType().Name.ToString();
if (bob == "TextBox")
return ((TextBox)controller).Text;
else if (bob == "ComboBox")
return ((ComboBox)controller).SelectedValue.ToString();
else
return "Invalid Object";
}
What I'd like to do is something like this:
Calling code:
TextBoxValue del = x => x.Text;
ComboBoxValue com = x => x.SelectedValue.ToString();
bob.returnText2(this.cboUnitType, com);
bob.returnText2(this.txtCurbAdj, del);
Function:
public string returnText2<T>(T controller, Func<T, string> lambda )
{
return lambda(controller);
}
I'm guessing I'm doing the generic side of things wrong, but I haven't been able to figure out the right way to do it.
Or maybe I'm completely out to lunch here.
Here's a cleaner (and clearer) version of your original code. It doesn't use any reflection, generics or ToString calls. Instead, it uses a pattern matching switch statement:
public static string ReturnText(Control control)
{
switch (control)
{
case TextBox tb:
return tb.Text;
case ComboBox cb:
return cb.SelectedText;
//etc.
default: return string.Empty;
}
}
By the way, your use of the name controller for a variable of type Control is misleading; controller has real meaning in other contexts.
An alternative would be to create a Dictionary<Type, Func<Control, string>> where an entry would look like {typeof(Textbox), c=>((TextBox)c).Text}, but I think that would be a lot less clear than just using a switch like I've shown.
One other thing: You could make this function an extension method on the Control type (by putting it in a static class and putting the keyword this before Control in the parameter list). I'd probably rename it GetTextValue. At that point, you could just say var textValue = anyControl.GetTextValue(); for any control on your page. Unfortunately, there isn't an extension property yet in C#
Using reflection is pretty easy. What you do is use the type of the class to retrieve their properties. Then you request the value of that property on an object and you got the value.
here a quick simple reflection. What it does is get the type of the object, request the property named SelectedValue then query the combobox object to retrieve the value and finally convert as string.
var combobox = this.cboUnitType;
var value = combobox.GetType().GetProperty("SelectedValue").GetValue(combobox ).ToString();
Here the same thing made into a function and quite generic plus has possible error handling
private string GetValue(object obj, string property)
{
var value = "";
try
{
value = obj.GetType().GetProperty(property).GetValue(obj).ToString();
}
catch { }
return value;
}

Convert Generic T to type C#

I'm trying to convert a generic method parameter to its type. The compiler is saying that I can't convert it
public ProvideRequest ProvideRequest<T>(int numberOfLines,
string ServiceType,
T addressIdentifier)
{
var provideRequest = new ProvideRequest();
provideRequest.NumberOfLines = numberOfLines;
provideRequest.ServiceType = ServiceType;
Type t = typeof(T);
switch (t.GetType().Name)
{
case nameof(GoldAddressKeyIdentifierType):
provideRequest.RequestIdentifier =
Convert.ChangeType(addressIdentifier, typeof(GoldAddressKeyIdentifierType))
break;
}
return provideRequest;
}
Any help with this would be appreciated.
The problem is that when calling t.GetType() you don´t get the generic type but simply System.Type which is the runtime-type of t. What you want instead is the name of the generic type, which you can get via :
switch(typeof(T).Name)
Furthermore Name returns a string, so you have to write your cases as follows:
case MyNamepscae.GoldAddressKeyIdentifierType:
However I´d strongly recommend not to lery on typenames, just make a switch on the actual type itself. However the switchstatement allows only strings, so use an if instead:
if(typeof(T) == typeof(GoldAddressKeyIdentifierType))
Type t = typeof(T); // type of T
switch (t.GetType().Name)
This switch is a mistake probably. t is of type Type. So t.GetType() is System.RuntimeType, so t.GetType().Name is always "System.RuntimeType" you know.
As far as I understand your problem, you need to remove .GetType(), you need
switch(t.Name)
I suggest comparing two Types:
...
if (typeof(T) == typeof(GoldAddressKeyIdentifierType))
provideRequest.RequestIdentifier =
Convert.ChangeType(addressIdentifier, typeof(GoldAddressKeyIdentifierType));
return provideRequest;
However, generics (<T>) should work as generic type, any special conditions are bad parctice.
Since you know it is of type GoldAddressKeyIdentifierType, you should be able to cast the object as the class in your case method
provideRequest.RequestIdentifier = (GoldAddressKeyIdentifierType)addressIdentifier;

How can I use an implict variable when return type contingent on switch statement

I want to be able to assign the results from a database query into a single, generic variable.
The issue is that each query returns a slightly different return type. I cannot initialize an implicit variable (i.e. var data;) as this gives an error.
The foreach statement performs the same operation on data so I'd like to populate data based on the viewtype parameter.
ITableRepository tableRepository = new TableRepository();
var data; \\Gives me an error
switch (viewtype)
{
case "overall": \\ type = IEnumerable<usp_GetTableRankingResult>
data = tableRepository.GetTableRanking(1, null);
break;
case "week": \\ type = IEnumerable<usp_GetTableRankingThisWeekResult>
data = tableRepository.GetTableRankingThisWeek(1, null);
break;
case "minileague": \\ type = IEnumerable<usp_GetTableRankingMimiLeagueResult>
data = tableRepository.GetTableRankingMiniLeague(1, null);
break;
}
foreach (var item in data) { //do some stuff }
I cannot initialize the data variable inside the switch statement and I cannot explicit declare the data variable upfront e.g. IEnumerable<usp_GetTableRankingResult> data as I don't know what type it will be until runtime.
Who can show me a way forward?
You can't separate declaration and initialisation when using var.
When you use var, you ask the compiler to guess the type based on the initialiser:
// v--------------- Set the type of the declared identifier "data"
// v-------- from the inferred type of its initializer
var data = ...
So you can only use var with an initialiser. Your var data; doesn't have any.
The way forward depends on what's in "do some stuff". I'd imagine something like
IEnumerable<SomeType> data;
switch (viewtype)
...
for some suitable type SomeType.
As #Queti mentions in his comment: let each of the GetTableRanking...() methods return an enumerable of a base type, like IEnumerable<TableRanking>.
Then you can declare data like this:
IEnumerable<TableRanking> data;
The compiler will then complain about the use of data in your foreach, because it may not have been initialized by the switch block. Select one default case (like overall) and promote that to default:
switch (viewtype)
{
// ...
default:
data = tableRepository.GetTableRanking(1, null);
break;
}
The idea here would be to Setup the Possible items as an inherited child of a base
public class usp_GetTableRankingResult{
// shared properties
}
public class usp_GetTableRankingsByWeek : usp_GetTableRankingResult{
// extra properies for this guy
}
public class usp_GetTableRankingsByDay : usp_GetTableRankingsResult{
// extra propries for this guy
}
// and so on
and when you're ready to implement you do this
IEnumerable<usp_GetTableRankingsResult> results;
switch(viewType){
case "overall":
results = new List<usp_GetTableRankingsResults>();
// fill results or use another implementation of IEnumerable or whatever...
break;
case "week":
results = new List<usp_GetTableRankingsResultsByWeek>();
// fill results or use another implementation of IEnumerable or whatever...
break;
case "day":
results = new List<usp_GetTableRankingsResultsByDay>();
// fill results or use another implementation of IEnumerable or whatever...
break;
}
and then later you can do something like this to get the result specific data
foreach(var result in results){
if (result is usp_GetTableRankinsResultByDay){
// do specifics if its by Day
}
// and so on
}

How to make a function private to a method?

I'm working on a method that needs to repeat a small operation at different spots, but the code to be repeated should be private to the method. The obvious solution is a nested function. Whatever I try however, the C# compiler barfs at me.
Something roughly equal to this Perl snippet:
my $method = sub {
$helper_func = sub { code to encapsulate };
# more code
&$helper( called whenever needed );
# more code
}
is what I am talking about, and what I'm trying to accomplish in C#.
No other method in the class should be able to access the helper function in this context. The most logical means of writing this construct in C#, as it appears to me would be something like this:
var helper = (/* parameter names */) => { /* code to encapsulate */ };
And actually make the compiler earn its keep.
Since such an assignment is forbidden, as is the equivalent using the older delegate(){} syntax in place of the lambda, and so is declaring a delegate type within a method—what csc actually allows me to write however, is this:
private delegate /* return type */ Helper(/* parameters */);
private /* return type */ method(/* parameters */) {
Helper helper = (/* parameter names */) => {
/* code to encapsulate */
};
// more code
helper( /* called whenever needed */ );
// more code
}
Which is all fine and dandy for not copy and pasting a chunk of code around and editing the parameters by hand but it leaks a private delegate type to the rest of the class rather than keeping it private to the method. Which defeats the purpose in the first place. Using goto statements and local variables for parameters would provide better encapsulation of "helper" in this context without sacrificing code reuse. If I wanted to simulate function calls by passing parameters through registers, I think would rather use an assembler. I haven't found an acceptable way of refactoring the code to avoid the problem altogether either.
So, is it even possible to force this Common Object Oriented Language to obey?
You actually can do this in C#.
Func<T1, T2, ..., TReturn> myFunc = (a, b, ...) =>
{
//code that return type TReturn
};
If you need an anonymous method of return type void use Action instead of Func:
Action<T1, T2, ...> myAction = (a, b, ...) =>
{
//code that doesn't return anything
};
If you are in C# 3.5 or higher you can take advantage of the lambdas and convenience delegate declarations Func<> and Action<>. So for instance
void DoSomething()
{
Func<int,int> addOne = (ii) => ii +1;
var two = addOne(1);
}
The reason you can't do
var addOne = (ii) => ii +1;
is because of Homoiconicity, the lambda can be interpreted as two different constructs, a delegate and an expression tree. Thus the need to be explicit in declaration.
If you explicitly type it, it will work, i.e.
Action<paramType1, paramType2> helperAction = (/* parameter names */) => { /* code to encapsulate */ };
Func<paramType1, paramType2, returnType> helperFunction = (/* parameter names */) => { /* code to encapsulate */ };
The reason var doesn't work is that a lambda expression can evaluate to multiple types (I believe either a delegate or expression tree, but don't quote me on that) and the compiler in this situation is unable to infer which was meant.
I recommend looking at the Action<T> and Func<TResult> delegates and their overloads. You can do something like this
static void Main(string[] args)
{
SomeMethod();
}
private static void SomeMethod()
{
Action<int> action = (num) => Console.WriteLine(num);
Enumerable.Range(1,10).ToList().ForEach(action);
Console.ReadKey();
}
Here SomeMethod is private and has a local Action<int> delgate that takes an int and does something to it.
I think the issue that you came across is that you can't use implicit typing (i.e. use var) when assigning a lambda expression to a variable.
You can't use the var keyword with lambdas or delegates because they both require additional context information (delegates require a return type, and lambdas require a return type and parameter types). For instance, the (params) => { code } syntax requires to be able to infer the parameter types and return types to work: you do this by explicitly giving it a type.
The generic System.Action delegate type (returns void) could do a good job at what you're trying:
Action<ArgumentType1, ArgumentType2, ...> myDelegate = (params) => { code };
Otherwise, there's also the System.Func, which has a return type, that must be passed as the last generic argument.
It depends on what your definition of hiding is.
The func/action solution (like the one Scott suggests)
void DoSomething()
{
Func<int,int> addOne = (ii) => ii +1;
var two = addOne(1);
}
Feals like hidding the method definition when writing regular C# code BUT is when looking at the IL equivalent of
//This is pseudo code but comes close at the important parts
public class Class1
{
//The actual type is different from this
private static Func<int, int> myMethod = AnonymousFunction;
public void f()
{
myMethod(0);
}
private static int AnonymousFunction(int i)
{
return 1;
}
}
So if you really want to get to the method from outside of the one "hidding" it you can do this with reflection The actual name generated for the field storing the delegate is illegal in C# bul valid in CLR context but that's the only thing that stand in the way of using the delegate as a regular delegate stored in a field (that is if you figue out the name :) )
It's quite simple actually. As the Method seems to have another responsibility than your current Class (why else would you hide this method) move your method into it's own Class and the part you want to have private into a private method in the new class.

Categories