Reputation: 13945
I would like to convert this (which is error prone)....
public static void GenerateReport(string report)
{
switch (report)
{
case "ReportA":
// do stuff
break;
case "ReportB":
// do stuff
break;
case "ReportC":
// do stuff
break;
}
}
To this....
public static void GenerateReport<T>()
{
switch (T) // BUT.... how do I handle this?
{
case ReportA:
// do stuff
break;
case ReportB:
// do stuff
break;
case ReportC:
// do stuff
break;
}
}
I have seen a LOT of questions that ask almost the same thing, but none of them have led me to an answer. Like this one, but for me, the solution provided in that thread flat out doesn't work. It throws multiple syntax errors when I try to compile. the solution there says:
switch typeof(T) {
//
}
Upvotes: 0
Views: 74
Reputation: 62213
Whenever you have if/switch statements where the code will execute differently depending on the input but produce generic output like what you have in your question it is usually a sign that you need to look into doing some refactoring.
In this case the best option would be to use an interface based design and move the logic for executing the various reports into their own types. This will allow you to better manage additional reports on an as needed basis without having to touch the existing code.
public interface IReporter {
void GenerateReport();
}
public class ReporterA : IReporter {
public void GenerateReport() { /* execute report */}
}
public class ReporterB : IReporter {
public void GenerateReport() { /* execute report */}
}
public class ReporterC : IReporter {
public void GenerateReport() { /* execute report */}
}
// The responsibilty of the factory is only to create the correct reporter based on the request
public class ReporterFactory{
public IReporter CreateReporter(string input){
/* the logic here can vary, you can get creative with Attributes
and name each report type and use reflection to create the
correct report type. You can also use an Enum and use that as an attribute value over
each Reporter type. There are many ways to handle it.
*/
}
}
/* your refactored method */
public static void GenerateReport(string report)
{
/* again, creation pattern could be based on something other than a string. It depends on how you want to differentiate your reporters*/
var reporter = new ReporterFactory().CreateReporter(report);
reporter.GenerateReport();
}
Upvotes: 1
Reputation: 7526
You can do it like this:
public static void RunIfEqual<TLeft, TRight>(Action action)
{
if (typeof(TLeft) == typeof(TRight))
{
action();
}
}
...
RunIfEqual<T, ReportA>(()=> ...);
RunIfEqual<T, ReportB>(()=> ...);
RunIfEqual<T, ReportC>(()=> ...);
Or even better way, you can define some ReportGeneratorFactory, that will choose which generator to use for this type and return it to you. Then you can just call GenerateReport on it.
Upvotes: 0
Reputation: 15892
You don't need generics for that, nor a switch statement with type detecting... instead use method overloading for each of the types and keep the do stuff pieces in their own methods...
public static void GenerateReport(ReportA a) { /*do stuff*/ }
public static void GenerateReport(ReportB b) { /*do stuff*/ }
public static void GenerateReport(ReportC c) { /*do stuff*/ }
Upvotes: 3
Reputation: 1062520
The key point about generics is that if the thing you are doing isn't roughly the same for each final T
, then it isn't actually generic and you shouldn't be doing it that way.
Good candidates here might include:
virtual
/ abstract
method)Type
instancebut... not generics. The reason the language isn't helping you is because this isn't a good fit. That said: you could do:
if(typeof(T) == typeof(Foo)) {
// foo
} else if (typeof(T) == typeof(Bar)) {
// bar
} ...
but; that is kinda missing the point of generics.
Upvotes: 1