Switch case on type c# [duplicate] - c#

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# - Is there a better alternative than this to 'switch on type'?
Hello suppose i get a big if/else on class type. it's there a way to do it with a switch case ?
Example :
function test(object obj)
{
if(obj is WebControl)
{
}else if(obj is TextBox)
{
}
else if(obj is ComboBox)
{
}
etc ...
I would like to create something like
switch(obj)
{
case is TextBox:
break;
case is ComboBox:
break;
}
}

Update C# 7
Yes: Source
switch(shape)
{
case Circle c:
WriteLine($"circle with radius {c.Radius}");
break;
case Rectangle s when (s.Length == s.Height):
WriteLine($"{s.Length} x {s.Height} square");
break;
case Rectangle r:
WriteLine($"{r.Length} x {r.Height} rectangle");
break;
default:
WriteLine("<unknown shape>");
break;
case null:
throw new ArgumentNullException(nameof(shape));
}
Prior to C# 7
No.
http://blogs.msdn.com/b/peterhal/archive/2005/07/05/435760.aspx
We get a lot of requests for addditions to the C# language and today
I'm going to talk about one of the more common ones - switch on type.
Switch on type looks like a pretty useful and straightforward feature:
Add a switch-like construct which switches on the type of the
expression, rather than the value. This might look something like
this:
switch typeof(e) {
case int: ... break;
case string: ... break;
case double: ... break;
default: ... break;
}
This kind of statement would be extremely useful for adding virtual
method like dispatch over a disjoint type hierarchy, or over a type
hierarchy containing types that you don't own. Seeing an example like
this, you could easily conclude that the feature would be
straightforward and useful. It might even get you thinking "Why don't
those #*&%$ lazy C# language designers just make my life easier and
add this simple, timesaving language feature?"
Unfortunately, like many 'simple' language features, type switch is
not as simple as it first appears. The troubles start when you look at
a more significant, and no less important, example like this:
class C {}
interface I {}
class D : C, I {}
switch typeof(e) {
case C: … break;
case I: … break;
default: … break;
}
Link: https://blogs.msdn.microsoft.com/peterhal/2005/07/05/many-questions-switch-on-type/

The following code works more or less as one would expect a type-switch that only looks at the actual type (e.g. what is returned by GetType()).
public static void TestTypeSwitch()
{
var ts = new TypeSwitch()
.Case((int x) => Console.WriteLine("int"))
.Case((bool x) => Console.WriteLine("bool"))
.Case((string x) => Console.WriteLine("string"));
ts.Switch(42);
ts.Switch(false);
ts.Switch("hello");
}
Here is the machinery required to make it work.
public class TypeSwitch
{
Dictionary<Type, Action<object>> matches = new Dictionary<Type, Action<object>>();
public TypeSwitch Case<T>(Action<T> action) { matches.Add(typeof(T), (x) => action((T)x)); return this; }
public void Switch(object x) { matches[x.GetType()](x); }
}

Yes, you can switch on the name...
switch (obj.GetType().Name)
{
case "TextBox":...
}

Here's an option that stays as true I could make it to the OP's requirement to be able to switch on type. If you squint hard enough it almost looks like a real switch statement.
The calling code looks like this:
var #switch = this.Switch(new []
{
this.Case<WebControl>(x => { /* WebControl code here */ }),
this.Case<TextBox>(x => { /* TextBox code here */ }),
this.Case<ComboBox>(x => { /* ComboBox code here */ }),
});
#switch(obj);
The x in each lambda above is strongly-typed. No casting required.
And to make this magic work you need these two methods:
private Action<object> Switch(params Func<object, Action>[] tests)
{
return o =>
{
var #case = tests
.Select(f => f(o))
.FirstOrDefault(a => a != null);
if (#case != null)
{
#case();
}
};
}
private Func<object, Action> Case<T>(Action<T> action)
{
return o => o is T ? (Action)(() => action((T)o)) : (Action)null;
}
Almost brings tears to your eyes, right?
Nonetheless, it works. Enjoy.

The simplest thing to do could be to use dynamics, i.e. you define the simple methods like in Yuval Peled answer:
void Test(WebControl c)
{
...
}
void Test(ComboBox c)
{
...
}
Then you cannot call directly Test(obj), because overload resolution is done at compile time. You have to assign your object to a dynamic and then call the Test method:
dynamic dynObj = obj;
Test(dynObj);

Related

Pass generic type parameter to Func

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.

How to access and create if statement variables C#

I'm trying to keep to the DRY principle in C#, and I was wondering if it's possible to access the argument checks in an if block. For example, would the below be possible?
if (foo == true || bar == false)
{
if (check0)
{
//foo is true
}
if (!check1)
{
//bar is false
}
}
I was also wondering if it's possible to do this, to keep the scope clean?:
if (var foo = runTimeAccessedVariable == "bar")
{
//we now have the runtime generated variable.
}
//but it doesn't exist here
Nope, it's not possible. In fact, since you use the short-circuiting || operator, the second check might not even be evaluated.
Obviously, you can work around it as follows:
var fooIsTrue = (foo == true);
var barIsFalse = (bar == false);
if (fooIsTrue || barIsFalse)
{
...
}
Note that this changes the behaviour of your code, since barIsFalse is always evaluated.
The scope and reuse can both be trivially solved by using a pair of brackets to define a new scope;
pulic void MyFunc()
{
// do stuff here in the scope of MyFunc
{
// create child scope with new scoping rules and declare control variables
var fooTrue = foo == true;
var barFalse = bar== false;
if (fooTrue || barFalse)
{
if (fooTrue)
{
//foo is true
}
if (barFalse)
{
//bar is false
}
}
}
// stuff here cannot access fooTrue, barFalse.
}
This stops the variables from 'leaking out' of this part of the function. There is a small semantic difference because the var barFalse line isn't shortcut, but it seems from your example that you'll probably need to test it anyway so it shouldn't be a concern.
Answering you second question, no it is not possible to declare a variable in this way. The only similar alternative is to use { } to create your own local scope and declare the local variable before the if statement:
{
bool foo;
if (foo = runTimeAccessedVariable == "bar")
{
}
}
In any case I'm not really sure what the benefits of this approach are. If you are insde the if statement, you already know foo is true, what is the use of having the scoped local?
Concerning your first question, I'd just push back on the whole approach. You are basically using an if statement based on a boolean expression made up of two or more conditions. Then, once inside the if statement you are discerning between what boolean condition is met or not. Also, you could have the case of an uninitialized variable, because check1 is not guaranteed to run.
I'd rewrite that completely and by-pass the need of any locally scoped variables:
Work is independent for each condition:
if (foo)
{
//whatever
}
else if (bar)
{
//whatever
}
There is common work for both conditions:
if (foo)
{
//whatever
if (bar)
{
//whatever
}
}
Both would be semantically equivalent to what you are proposing.
You can actually. You can use (extension) methods like this:
// For first case.
public static void If(this Lazy<bool>[] checks, Predicate<Lazy<bool>[]> ifCondition, Action<Lazy<bool>[]> ifAction) {
if (ifCondition(checks)) ifAction(checks);
}
// For second case.
public static void If(this object[] variables, Predicate<object[]> ifCondition, Action<object[]> ifAction) {
if (ifCondition(variables)) ifAction(variables);
}
And use of it would look like this:
// First case.
new[] { new Lazy<bool>(() => foo == true), new Lazy<bool>(() => bar == false) }.
If(checks => checks[0].Value || checks[1].Value, checks => {
if (checks[0].Value) {
//foo is true
}
if (!checks[1].Value) {
//bar is false
}
});
// Second case.
new[] { "bar" }.If(variables => (string)variables[0] == "bar", variables => {
//we now have the runtime generated variable.
});
This will limit the scope of those temporary values. However, this does not provide any check for whether you actually using checks or variables in the right way. And it would be harder to debug if something goes wrong then simple if statement.
This could also be extended to accept Func instead of Action that your If method could return result as well. And it is possible to even add ElseIf and Else methods to chain with If method (to mimic all if statement behavior).

getting property names at compile time without using magic string, similar to T4MVC concept

Sometimes, I need to get the string equivalent of a property name or expression. Most of the time this is for some serialization or ORM-mappings. The use is irrelevant. Instead of typing the string as a "magic string", e.g
var sPropertyName = "PropertyId";
I use reflection, so that if it changes, it is automatically updated. Example:
public void test()
{
var sPropertyName = GetPropertyName<Property>(x => x.PropertyId);
}
public static string GetPropertyName<T>(Expression<Func<T, object>> selector)
{
return (PropertyInfo)GetMemberInfoBySelector(selector);
}
public static MemberInfo GetMemberInfoBySelector(Expression selector)
{
Expression body = selector;
if (body is LambdaExpression)
{
body = ((LambdaExpression)body).Body;
}
switch (body.NodeType)
{
case ExpressionType.Call:
return (((System.Linq.Expressions.MethodCallExpression)body).Method);
case ExpressionType.MemberAccess:
return ((PropertyInfo)((MemberExpression)body).Member);
case ExpressionType.Convert:
{
UnaryExpression unaryExp = (UnaryExpression)body;
var op = unaryExp.Operand;
System.Linq.Expressions.MemberExpression memberExp = (MemberExpression)op;
return memberExp.Member;
}
default:
throw new InvalidOperationException("Cannot retrieve member info from selector!");
}
}
Sometimes, this is called quite often for batch-processing, or similar processing. I find it a waste that this resorts to reflection, when the value can actually be a constant. In cases where it is used a lot, this can slow things down quite a bit.
I know there exists a tool for ASP.Net MVC - T4MVC which scans the files and creates static classes with the property names.
In this case, something ideal would be where I could just use say
var sPropertyName = GeneratedMetaData.MyNamespace.Property.PropertyId
Is this somehow possible? I know I can store these constants myself on app start, but wanted to know if there is something automatic like T4MVC is.
Or maybe other approaches which does the same thing?

Switch statement with non-constant-expression - Extends C#/IDE ability

Before you start criticizing and pointing me §8.7.2 of C# specification, read carefully :)
We all know how switch looks like in C#. Ok so consider the class MainWindow with "nasty" Bar method
static int barCounter = 0;
public static int Bar()
{
return ++barCounter;
}
Somewhere in this class we have code like this
Action switchCode = () =>
{
switch (Bar())
{
case 1:
Console.WriteLine("First");
break;
case 2:
Console.WriteLine("Second");
break;
}
};
switchCode();
switchCode();
In the console window we will see
First
Second
Using Expressions in C# we could do the same – writing much same code
var switchValue = Expression.Call(typeof(MainWindow).GetMethod("Bar"));
var WriteLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) });
var #switch = Expression.Switch(switchValue,
Expression.SwitchCase(
Expression.Call(WriteLine, Expression.Constant("First")),
Expression.Constant(1)
),
Expression.SwitchCase(
Expression.Call(WriteLine, Expression.Constant("Second")),
Expression.Constant(2)
)
);
Action switchCode = Expression.Lambda<Action>(#switch).Compile();
switchCode();
switchCode();
In DebugView we could see "code behind" this expression
.Switch (.Call WpfApplication1.MainWindow.Bar()) {
.Case (1):
.Call System.Console.WriteLine("First")
.Case (2):
.Call System.Console.WriteLine("Second")
}
Ehmm, what if we use Expression.Call instead Expression.Constant?
public static bool foo1() { return false; }
public static bool foo2() { return true; }
// .....
var foo1 = Ex.Call(typeof(MainWindow).GetMethod("foo1"));
var foo2 = Ex.Call(typeof(MainWindow).GetMethod("foo2"));
var switchValue = Ex.Call(typeof(MainWindow).GetMethod("Bar"));
var WriteLine = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) });
var #switch = Ex.Switch(Ex.Constant(true),
Ex.SwitchCase(
Ex.Call(WriteLine, Ex.Constant("First")),
foo1
),
Ex.SwitchCase(
Ex.Call(WriteLine, Ex.Constant("OK!")),
Ex.Equal(switchValue, Ex.Constant(2))
),
Ex.SwitchCase(
Ex.Call(WriteLine, Ex.Constant("Second")),
foo2
)
);
Action switchCode = Ex.Lambda<Action>(#switch).Compile();
switchCode();
switchCode();
Console window shows, as we expected
Second
OK!
And DebugView
.Switch (True) {
.Case (.Call WpfApplication1.MainWindow.foo1()):
.Call System.Console.WriteLine("First")
.Case (.Call WpfApplication1.MainWindow.Bar() == 2):
.Call System.Console.WriteLine("OK!")
.Case (.Call WpfApplication1.MainWindow.foo2()):
.Call System.Console.WriteLine("Second")
}
So it is possible to use non-constant expression in case-statement :)
Ok, I known this is little ‘messy’ code. But here comes my question (finally :P):
Is there any way to extends functionality of IDE/VisualStudio/compiler to do this, but with more elegant code?
Something like this
switch (true)
{
case foo1():
Console.WriteLine("First");
break;
case Bar() == 2:
Console.WriteLine("OK!");
break;
case foo2():
Console.WriteLine("Second");
break;
}
I know this will be some extension and code will be not the same (not the same performance). But I wonder if this is even possible to "change" code on-the-fly – like anonymous function or yield return is transform to nested class.
I hope someone goes through the above text and leave some clue.
In general, there are no extension points in the Microsoft C# compiler as far as I know (and even Roslyn isn't planning to change that). But nothing is stopping you from writing your own C# compiler, or, more realistically, modifying the open source Mono C# compiler.
In any case, I think it's much more trouble than what it's worth.
But maybe you can do what you want using something that's already in the language, namely, lambdas and method calls, to form a “fluent switch”:
Switch.Value(true)
.Case(() => Foo(), () => Console.WriteLine("foo"))
.Case(() => Bar() == 2, () => Console.WriteLine("bar == 2"));
If you don't mind that all the condition values will be evaluated every time, you simplify that a bit:
Switch.Value(true)
.Case(Foo(), () => Console.WriteLine("foo"))
.Case(Bar() == 2, () => Console.WriteLine("bar == 2"));
No, it's not possible, nor that I'm aware of. It's already kind of miracle that you can use a string inside switch statement (reference type with immutable behavior). For these kind of cases just use if, if/else, if/elseif combinations.
There aren't currently extensions that do that sort of thing. Although it's worth pointing out that MS SQL allows for exactly what you are looking for
SELECT
Column1, Column2,
CASE
WHEN SomeCondition THEN Column3
WHEN SomeOtherCondition THEN Column4
END AS CustomColumn
FROM ...
The problem with this becomes understanding precedence; what happens when both conditions are true? In SQL the case statement returns the value from the first statement that is true, and ignores other cases, but that behavior might not be what you wanted.
The strength of C# is that it's impossible to code switches in such a way that both case 1 and case 2 can be true at the same time, so you are guaranteed only one correct answer.
As we all know "Switches" exposes a similar functionality to an if. Most of us (myself include) see it as a syntax sugar -- it's easier to read a bunch of cases on a certain switch then read through a number of if/else if/.../else. But the fact is that switch is no syntax sugar.
What you must realize is that the code generated for switch (be it IL or machine code) is not the same as the code generated for sequential ifs. Switch has a nice optimization which, as #Ed S. already pointed out, enables it to run in a constant time.

How to get the string (of source-code) that generated a lambda-expression?

(for LISP hackers in short: I'm looking for the LISP-quote equivalent in C#)
I'm trying to write a meaningful ToString-method for a class which has a Func as member. Experiened API-users can set this member via setter-method like
myClassObject.SetFunction( (x) => x*x );
Now, when I use the ToString-method on the member it only returns
System.Func<double,double>
which is not very helpful. What would be helpful is
"(x) => x*X"
Is there any (preferable easy) way to do that?
Thanks for any help or comments.
Edit: corrected some typos
Expression<Func<double,double>> expr = x => x * x;
string s = expr.ToString(); // "x => (x * x)"
If you're willing to store your delegate as an expression, you can achieve what you want. The code would look something like this:
private Expression<Func<double, double>> myFunc;
private Func<double, double> cachedDelegate;
public void SetFunc(Expression<Func<double,double>> newFunc)
{
this.myFunc = newFunc;
this.cachedDelegate = null;
}
public double ExecFunc(double x)
{
if (this.myFunc != null)
{
if (this.cachedDelegate != null)
{
return this.cachedDelegate(x);
}
else
{
this.cachedDelegate = this.myFunc.Compile();
return this.cachedDelegate(x);
}
}
return 0.0;
}
public string GetFuncText()
{
if (this.myFunc != null)
{
return this.myFunc.ToString();
}
return "";
}
In order to actually use the lambda expression, you have to compile it first. Storing it in a delegate means you only take that hit once.
Also, this approach means that users have to use a lambda, since method groups aren't convertible to Expression<Func<>>. That's not a huge concern, though, since instead of passing MyMethod, a user could pass x => MyMethod(x).
The calling code would look something like this:
myObject.SetFunc(x => 2*x);
Console.WriteLine(myObject.GetFuncText());
One final note is that the above sample is not thread-safe, so if you expect to have the methods called from multiple threads, some sort of synchronization would be appropriate.
None that I know of since that string has never entered the system, only IL was somehow generated and stored with a reference... you would need to "decompile" the IL to some meaningful string...
With CodeExpression there is possibility to call GenerateCodeFromExpression via an instance of CodeDomProvider which has built-in implementations for C# / VB / JScript... but I would be surprised if that met your needs...
Another option: With Expression you could use ToString() - this works with LambdaExpression too since that is just a descendant.

Categories