C# Simple Type w/ Generic Type - c#

I want to do different things with a generic type given that it is a byte array, int, etc.
public void GenericType<T>(T Input)
{
switch (typeof(T))
{
case (typeof(byte[])):
break;
case (typeof(int)):
case (typeof(float)):
case (typeof(long)):
break;
case (typeof(string)):
break;
default:
throw new Exception("Type Incompatability Error");
break;
}
}
Sandbox.cs(12,13): error CS0151: A switch expression of type `System.Type' cannot be converted to an integral type, bool, char, string, enum or nullable type
add:
My specific case has some code that is generic and some code that is specific. I also have one where I do not actually pass a T variable. Solutions thus far work if there is a variable.
public void GenericType<T>()
Not being terribly experienced, what is the best practice in C#?
Thank you.

You can do this with switch using pattern matching:
switch(Input)
{
case int i:
// do something with i
case string x:
// do something with x
}

You might try something like
if (Input is int i) { DoSomething(i) ; }
else if (Input is long l) { DoSomething(l) ; }
Best? Maybe. Works? Yup.
You are effectively calling System.Object GenericType in this example.

Related

Better If statement with type checking C#

I'm currently working on a .NET 4.7.1 application. I have an If-statement to check the data type and call an handler method accordingly.
My current If statement looks like this:
// object msg = MyHelper.Deserialize(xmlString);
if (msg is Tomato) Handle_Tomato((Tomato)msg);
if (msg is Apple) Handle_Apple((Apple)msg);
if (msg is Banana) Handle_Banana((Banana)msg);
if (msg is Orange) Handle_Orange((Orange)msg);
msg is basically an object deserialized from a string.
I was wondering, if there is a better way to write my if statements?
Thank you very much!
As Sweeper mentions in the comments, from C# 7.0 you can use the The is type pattern expression
if (msg is Tomato tomato) Handle_Tomato(tomato);
You could also use pattern matching with a switch statement (Type pattern) since C# 7.0
The type pattern enables concise type evaluation and conversion. When
used with the switch statement to perform pattern matching, it tests
whether an expression can be converted to a specified type and, if it
can be, casts it to a variable of that type.
switch(msg)
{
case Tomato tomato : Handle_Tomato(tomato); break;
case Apple apple : Handle_Apple(apple); break;
...
}
I'd strongly suggest not to do such checks. What if in the future there are dozens of different types? Your if statement will increase and be unmaintainable. What if the type changes? You'd have to change all the if statements as well.
You could solve this by using an interface. You already have the classes.
interface IHandler
{
void Execute();
}
class Orange : IHandler
{
public void Execute()
{
// do your orange stuff
}
}
class Tomato : IHandler
{
public void Execute()
{
// do your tomato stuff
}
}
It can be called like this.
if (msg is IHandler) ((IHandler)msg).Execute();
I think the easiest would be to use a switch/case
switch (msg)
{
case Tomato t:
Handle_Tomato(t);
break;
case Apple a:
Handle_Apple(a);
break;
case Banana b:
Handle_Banana(b);
break;
case Orange o:
Handle_Orange(o);
break;
}
Use a dictionary. I foresee your if will explode with new cases in future, generally speaking, walls of if and large switch statements are bad code. In a similar situation I created something like this:
private static readonly Dictionary<RuntimeTypeHandle, Action<object>> handleMsgImplementations = new Dictionary<RuntimeTypeHandle, Action<object>>
{
{ typeof(Tomato).TypeHandle, x => Handle_Tomato((Tomato)x) },
// etc...
};
// Then instead of if, use this (prepare a catch for Invalid Key or use a TryGetValue)
handleMsgImplementations[msg.GetType().TypeHandle](msg);
I get TypeHandle because I like to use a value type for the key.
EDIT: #TheGeneral answer is the best, also, the C# compiler creates a dictionary under the hood when the amount cases starts to damage performance. I keep my answer because I believe adds value.

How should I convert enum type to string in C# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have an enum inside a class called cConstsAndEnums:
public class cConstsAndEnums
{
public enum EnSelectedKtovet
{
En_KtovetMaam = 1,
En_KtovetTmg
};
}
In other class I have switch:
switch (dr["rowSelectedKtovet"].ToString())
{
case cConstsAndEnums.EnSelectedKtovet.En_KtovetMaam:
doSomthing;
break;
default:
}
The problem is that I'm getting an error:
Cannot implicitly convert type 'cConstsAndEnums.EnSelectedKtovet' to 'string'.
I try to do:
case (string)cConstsAndEnums.EnSelectedKtovet.En_KtovetMaam:
but I have error:
Cannot convert type 'cConstsAndEnums.EnSelectedKtovet' to 'string'.
Tried also:
case Convert.ToString(cConstsAndEnums.EnSelectedKtovet.En_KtovetMaam):
but again I have error:
A constant value is expected.
Please help.
Thanks.
The reason is the data type of the switch (string) is different to your cases (enum values). Trying to solve this by using .ToString() means you are doing an operation, but a case needs always a constant value. Do it the other way and cast the string to the enum before using it at the switch.
cConstsAndEnums.EnSelectedKtovet enumValue = (cConstsAndEnums.EnSelectedKtovet)
Enum.Parse(typeof(cConstsAndEnums.EnSelectedKtovet, dr["rowSelectedKtovet"].ToString());
switch (enumValue)
{
case cConstsAndEnums.EnSelectedKtovet.En_KtovetMaam:
...
}
Also think about to store the numeric value of the enumeration instead of the string value. Every enum literal has a value which you can simply cast to an integer:
EnSelectedKtovet enumValue = EnSelectedKtovet.En_KtovetMaam;
int storedEnumValue = (int)enumValue;
EnSelectedKtovet restoredEnumValue = (EnSelectedKtovet)storedEnumValue;
With this solution you dont need to deal with any string, which is much more safe and comfortable.
You should use Enum.Parse() method (in case if you ensure that string has always prvoded enum value) or Enum.TryParse() (in case if string cuold have anything, so you can set your enum to default value)
In your case try this:
var myEnum = (EnSelectedKtovet)Enum.Parse(typeof(EnSelectedKtovet), dr["rowSelectedKtovet"].ToString());
switch (myEnum)
{
case EnSelectedKtovet.En_KtovetMaam:
doSomthing;
break;
default:
}
In your switch statement, convert it to the enum
switch(Enum.Parse(typeof(EnSelectedKtovet), dr["rowSelectedKtovet"].ToString()){
case cConstsAndEnums.EnSelectedKtovet.En_KtovetMaam:
doSomthing;
break;
default:
}
switch ((EnSelectedKtovet)int.Parse(dr["rowSelectedKtovet"].ToString()))
{
case EnSelectedKtovet.En_KtovetMaam:
break;
default:
break;
}
I hope it will work for you.
This is a case of the XY Problem. You are asking about your attempted solution, not the actual problem.
In this case the actual problem is that you read an enum value from the database. The index method returns an object so you can't compare it with anything else directly. You'd have to cast it to an int (if the database returns an int) or a string. You can cast it to an enum directly too, since enums are basically named integers.
Instead of that, you tried to convert it to a string. When you tried to compare that string to the enum values, you got a compilation error because obviously an enum isn't a string.
If the underlying field value is an integer, you can just cast it to the enum's type:
var value=(cConstsAndEnums.EnSelectedKtovet)dr["rowSelectedKtovet"];
switch (value)
{
case cConstsAndEnums.EnSelectedKtovet.En_KtovetMaam:
doSomthing;
break;
default:
}
If it's a string that contains the enum name, you'll have to parse the string with Enum.Parse or Enum.TryParse
var fieldValue=(string)dr["rowSelectedKtovet"];
var value=Enum.Parse(typeof(cConstsAndEnums.EnSelectedKtovet),fieldValue);
switch (value)
...
With a bit of C# 7 and pattern matching magic, you could match both cases:
var value=dr["rowSelectedKtovet"];
switch(value)
{
case int val when Enum.IsDefined(typeof(cConstsAndEnums.EnSelectedKtovet),val) :
var enumValue=(cConstsAndEnums.EnSelectedKtovet)val;
//Use enumValue
break;
case string s when Enum.TryParse<cConstsAndEnums.EnSelectedKtovet>(s,out var enumValue):
//Use enumValue
break;
default :
throw new ArgumentException($"Unknown {value}");
}
You Can try.ToString("D") to compare with Enum value.
string selectedValue= dr["rowSelectedKtovet"].ToString();
if(selectedValue==cConstsAndEnums.EnSelectedKtovet.En_KtovetMaam.ToString("D"))
{
doSomthing();
}

Having a problem using switches in C#

I'm getting the error "A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type" in my code at the line,
switch (job_selecter.SelectedValue)
Here's my code:
private void start()
{
switch (job_selecter.SelectedValue)
{
case 0:
head_seal_label.Text = "Ravager's Seal: Head (8)";
break;
}
}
Could anyone tell me why this is happening and how I can fix it? Thanks!
job_selecter.SelectedValue is probably an object.
private void start()
{
int index = (int)job_selecter.SelectedValue;
switch (index )
{
case 0:
head_seal_label.Text = "Ravager's Seal: Head (8)";
break;
}
}
It seems like what you really want to do is this:
switch(job_selecter.SelectedIndex)
{
case 0:
// do whatever
break;
default:
// handle default case
break;
}
You've noted in one of your responses that casting SelectedValue to string or int or whatever can cause a null reference exception if you then use it in a switch--which makes perfect sense, because it's perfectly legal for a combo box to have nothing selected, and you're going to need to account for that case. If you switch on SelectedIndex, handling -1 will allow you to handle a case of "no selection" specifically.
Of course, it's worth pointing out that switching on SelectedIndex only makes sense if the combo box contains a known, unchanging set of values. Adding or removing values will potentially cause the indices of everything in the box to change, thus breaking the switch.
SelectedValue is an object. cast it to an int in the switch.
You might have meant to use "SelectedIndex" property (a zero based number corresponding to your selection in combo OR a -1 when nothing is selected):
switch (job_selecter.SelectedIndex)
{
case 0:
head_seal_label.Text = "Ravager's Seal: Head (8)";
break;
// other cases for other Indices
case -1:
default:
// handle nothing selected...
}
You should get your SelectedIndex into an int first, to deal with this error " "A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type" in my code at the line":
int index;
if(!Int32.TryParse(job_selector.SelectedIndex.ToString(), out index))
{
index = -1;
}
//All your other cases here
switch(index)
{
case 0:
head_seal_label.Text = "Ravager's Seal: Head (8)";
break;
default:
head_seal_label.Text = "Some default Value";
break;
}

Convert between System.Data.SqlDbType and Microsoft.SqlServer.Management.Smo.SqlDataType

Given an instance of System.Data.SqlDbType how can I convert it to an instance of Microsoft.SqlServer.Management.Smo.SqlDataType and vice-versa?
The enums don't match up.
Something like this if the names match, maybe?
System.Data.SqlDbType otherEnumTypeValue = System.Data.SqlDbType.Xml;
Microsoft.SqlServer.Management.Smo.SqlDataTypeconverted =
(Microsoft.SqlServer.Management.Smo.SqlDataType)Enum.Parse(typeof(Microsoft.SqlServer.Management.Smo.SqlDataType), otherEnumTypeValue.ToString());
Conversion from SqlDataType to SqlDbType using Bala R's enum parsing code plus special cases for unsupported conversions.
private static SqlDbType ConvertSqlTypeEnum(SqlDataType sqlDataType)
{
SqlDbType sqlDbType;
switch (sqlDataType)
{
case SqlDataType.UserDefinedType:
sqlDbType = System.Data.SqlDbType.Udt;
break;
case SqlDataType.None:
case SqlDataType.NVarCharMax:
case SqlDataType.UserDefinedDataType:
case SqlDataType.VarBinaryMax:
case SqlDataType.VarCharMax:
case SqlDataType.SysName:
case SqlDataType.Numeric:
case SqlDataType.UserDefinedTableType:
case SqlDataType.HierarchyId:
case SqlDataType.Geometry:
case SqlDataType.Geography:
throw new NotSupportedException("Unable to convert to SqlDbType:" + sqlDataType);
default:
sqlDbType = (SqlDbType)Enum.Parse(typeof(SqlDbType), sqlDataType.ToString());
break;
}
return sqlDbType;
}
The reverse should be simpler with only Udt and Structured requiring special handling.

using switch statements with constants or enumerations? (Which is better)? C#

HI, I've got a simple question, but one that has been bugging me for a while.
Question:
When using switch statements in C#, is it considered better practice to use enums over constants or vice versa? Or is it a matter of preference? I ask this because many people seem to like using enums, but when you are switching on an int value, you have to cast each of the values contained in the enum to an int, even if you specify the type of enum.
Code Snippet:
class Program
{
enum UserChoices
{
MenuChoiceOne = 1,
MenuChoiceTwo,
MenuChoiceThree,
MenuChoiceFour,
MenuChoiceFive
}
static void Main()
{
Console.Write("Enter your choice: ");
int someNum = int.Parse(Console.ReadLine());
switch (someNum)
{
case (int)UserChoices.MenuChoiceOne:
Console.WriteLine("You picked the first choice!");
break;
// etc. etc.
}
}
}
Is there some way you can create an instance of the enum and just cast the whole enum to an int?
Thanks!
Why not do this instead?
UserChoices choice = (UserChoices)int.Parse(Console.ReadLine());
switch (choice)
{
case UserChoices.MenuChoiceOne:
// etc...
Then you only need to cast once.
Update: fixed bug in code!
I think the preference of enums over constants is because of readability and not because of performance. I find it easier to read enums in code (in general and not just in switch statements), than to read/understand constants and their usage.
and btw, you don't have to cast every case, you can just cast your switch.
switch((UserChoices)someEnum)
{
...
I believe you can simply do:
switch((UserChoices)someNum)
{
case UserChoices.MenuChoiceOne:
break;
default:
throw Exception // whatever here
}

Categories