C#: how assign a value to a string var without using switch - c#

First of all I must say that I am pretty new using C#. I have written this code block to assign a value to a string var depending on the value of another var. I have used the Switch statement:
switch (_reader.GetString(0))
{
case "G":
permiso.Area = "General";
break;
case "SIS":
permiso.Area = "Sistems";
break;
case "SOP":
permiso.Area = "Development";
break;
case "HLP":
permiso.Area = "Support";
break;
}
Can I make this in an easier way in C#?
Thanks!

You can use Dictionary<string, string>(), which can store your "switch case" string as key and "switch case value" in value.
Example:
var dict = new Dictionary<string, string>()
{
{"G", "General"},
{"SIS", "Sistems"},
...
}
So your code in order to access will be:
var key = _reader.GetString(0);
if(dict.TryGetValue(key, out var value)
{
permiso.Area = value;
}
else
{
// handle not exists key situation
}

Modern C# has a pattern matching switch
permiso.Area = _reader.GetString(0) switch {
"G" => "General",
"SIS" => "Sistems",
"SOP" => "Development",
"HLP" => "Support",
_ => throw new InvalidOperationException($"The value {_reader.GetString(0)} is not handled")
};
C# will complain at you if you don't include the "else" at the end _ =>

I mean if exists in C# somo sentence that makes something like that: my_string=my_string.decode(old_value0,new_value0, old_value1,new_value1, ...)
If you're after something like Oracle's DECODE, you can write it:
string Decode(string expr, params string[] arr){
for(int i = 0; i < arr.Length; i+=2)
if(arr[i] == expr)
return arr[i+1];
return arr.Length % 2 == 0 ? null : arr[arr.Length-1];
}
You'd use it like:
permiso.Area = Decode(reader.GetString(0), "G", "General", "SIS", "Sistems", "SOP", "Development", "HLP", "Support");
If you want an ELSE, pass an odd length array (something after the "Support")
If you want to be able to call it on a string, such as reader.GetString(0).Decode("G" ...) you can declare it in a static class and precede the first argument with this :
static string Decode(this string expr, ....)
That will make it an extension method, so it can be called "on a string"

If you either have same mappings occur on multiple locations or generally use the same strings repeatingly (in conditions, e.g.), a more sophisticated and cleaner approach would be to use enums and their descriptions in the first place. This makes the code more readable as you can (and should) use the unique enum in the code and catch its description when needed.
You need this enum extension method to read enum descriptions:
using System;
using System.ComponentModel;
public static string Description(this Enum source) {
DescriptionAttribute[] attributes = (DescriptionAttribute[])source
.GetType()
.GetField(source.ToString())
.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes.Length > 0 ? attributes[0].Description : string.Empty;
}
Prepare the enum and its corresponding dictionary mappers. If possible, those enums should only have one unique description but you can define additional mapper dictionaries to your likings, e.g. when you need a simple short to long text mapper as in your example.
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
// enum and its description
public enum PermissionArea {
[Description("Development")]
Development = 1,
[Description("General")]
General,
[Description("Sistems")]
Sistems,
[Description("Support")]
Support
}
public static class MyEnumDicts {
// default mapping of enum to its description
public static readonly Dictionary<PermissionArea, string> PermissionAreaToText = new Dictionary<PermissionArea, string>() {
{ PermissionArea.Development, PermissionArea.Development.Description() },
{ PermissionArea.General, PermissionArea.General.Description() },
{ PermissionArea.Sistems, PermissionArea.Sistems.Description() },
{ PermissionArea.Support, PermissionArea.Support.Description() }
};
// mapping of enum to short text
// (only if needed as it is better to only use one unique
// value which is already set as description in the enum itself
public static readonly Dictionary<PermissionArea, string> PermissionAreaToShortText = new Dictionary<PermissionArea, string>() {
{ PermissionArea.Development, "SOP" },
{ PermissionArea.General, "G" },
{ PermissionArea.Sistems, "SIS" },
{ PermissionArea.Support, "Support" }
};
// add reverse mappers via linq
public static readonly Dictionary<string, PermissionArea> TextToPermissionArea = PermissionAreaToText.ToDictionary(m => m.Value, m => m.Key);
public static readonly Dictionary<string, PermissionArea> ShortTextToPermissionArea = PermissionAreaToShortText.ToDictionary(m => m.Value, m => m.Key);
}
The usage could be as follows:
public void MyMethod(string permissionAreaShortText) {
try {
// map to enum (no switch or ifs etc. needed here)
PermissionArea permissionArea = MyEnumDicts.ShortTextToPermissionArea[permissionAreaShortText];
// now you can work via enums and do not
// have to hassle with any strings anymore:
switch (permissionArea) {
case PermissionArea.Development: ...; break;
case PermissionArea.General: ...; break;
case PermissionArea.Sistems: ...; break;
case PermissionArea.Support: ...; break;
}
// output/use its description when needed:
string permissionAreaText = permissionArea.Description();
// ...
} catch (Exception ex) {
// error handling: short text is no permission area
// ...
}
}

Related

C# Trying to mask child values in a dynamic object

At the moment I'm adding functionality to our service that will take in an object that is about to be logged to trace and mask any sensitive fields that are included in the object.
The issue is that we can get objects with different layers. The code I have written so far only handles a parent field and a single child field and uses a nasty embedded for loop implementation to do it.
In the event that we have a third embedded layer of fields in an object we want to log, this wouldn't be able to handle it at all. There has to be a more efficient way of handling generic parsing of a dynamic object, but so far it's managed to avoid me.
The actual code that deserializes and then masks field sin the object looks like this:
private string MaskSensitiveData(string message)
{
var maskedMessage = JsonConvert.DeserializeObject<dynamic>(message);
LoggingProperties.GetSensitiveFields();
for (int i = 0; i < LoggingProperties.Fields.Count(); i++)
{
for (int j = 0; j < LoggingProperties.SubFields.Count(); j++)
{
if (maskedMessage[LoggingProperties.Fields[i]] != null)
{
if (maskedMessage[LoggingProperties.Fields[i]][LoggingProperties.SubFields[j]] != null)
{
maskedMessage[LoggingProperties.Fields[i]][LoggingProperties.SubFields[j]] = MaskField(LoggingProperties.SubFieldLengths[j]);
}
}
}
}
return maskedMessage.ToString(Formatting.None);
}
And it works off of a LoggingProperties class that looks like this:
public static class LoggingProperties
{
// Constants indicating the number of fields we need to mask at present
private const int ParentFieldCount = 2;
private const int SubFieldCount = 4;
// Constant representing the character we are using for masking
public const char MaskCharacter = '*';
// Parent fields array
public static string[] Fields = new string[ParentFieldCount];
// Subfields array
public static string[] SubFields = new string[SubFieldCount];
// Array of field lengths, each index matching the subfield array elements
public static int[] SubFieldLengths = new int[SubFieldCount];
public static void GetSensitiveFields()
{
// Sensitive parent fields
Fields[0] = "Parent1";
Fields[1] = "Parent2";
// Sensitive subfields
SubFields[0] = "Child1";
SubFields[1] = "Child2";
SubFields[2] = "Child3";
SubFields[3] = "Child4";
// Lengths of sensitive subfields
SubFieldLengths[0] = 16;
SubFieldLengths[1] = 16;
SubFieldLengths[2] = 20;
SubFieldLengths[3] = 3;
}
}
}
The aim was to have a specific list of fields for the masking method to look out for that could be expanded or contracted along with our systems needs.
The nested loop method though just seems a bit roundabout to me. Any help is appreciated.
Thanks!
UPDATE:
Here's a small example of a parent and child record that would be in the message prior to the deserialize call. For this example say I'm attempting to mask the currency ID (So in properties the fields could be set like this: Parent1 = "Amounts" and Child1 = "CurrencyId"):
{
"Amounts":
{
"Amount":20.0,
"CurrencyId":826
}
}
An example of a problem would then be if the Amount was divided into pounds and pence:
{
"Amounts":
{
"Amount":
{
"Pounds":20,
"Pence":0
},
"CurrencyId":826
}
}
This would another layer and yet another embedded for loop...but with that I would be making it overly complex and difficult if the next record in a message had only two layers.
Hope this clarifies a few things =]
Okay, I've really tried but I couldn't figure out an elegant way. Here's what I did:
The first try was using reflection but since all the objects are of type JObject / JToken, I found no way of deciding whether a property is an object or a value.
The second try was (and still is, if you can figure out a good way) more promising: parsing the JSON string into a JObject with var data = JObject.Parse(message) and enumerating its properties in a recursive method like this:
void Mask(data)
{
foreach (JToken token in data)
{
if (token.Type == JTokenType.Object)
{
// It's an object, mask its children
Mask(token.Children());
}
else
{
// Somehow mask it but I couldn't figure out to do it with JToken
// Pseudocode, it doesn't actually work:
if (keysToMask.Contains(token.Name))
token.Value = "***";
}
}
}
Since it doesn't work with JTokens, I've tried the same with JProperties and it works for the root object, but there's a problem: although you can see if a given JProperty is an object, you can not select its children object, JProperty.Children() gives JToken again and I found no way to convert it to a JProperty. If anyone knows how to achieve it, please post it.
So the only way I found is a very dirty one: using regular expressions. It's all but elegant - but it works.
// Make sure the JSON is well formatted
string formattedJson = JObject.Parse(message).ToString();
// Define the keys of the values to be masked
string[] maskedKeys = {"mask1", "mask2"};
// Loop through each key
foreach (var key in maskedKeys)
{
string original_pattern = string.Format("(\"{0}\": )(\"?[^,\\r\\n]+\"?)", key);
string masked_pattern = "$1\"censored\"";
Regex pattern = new Regex(original_pattern);
formatted_json = pattern.Replace(formatted_json, masked_pattern);
}
// Parse the masked string
var maskedMessage = JsonConvert.DeserializeObject<dynamic>(formatted_json);
Assuming this is your input:
{
"val1" : "value1",
"val2" : "value2",
"mask1" : "to be masked",
"prop1" : {
"val3" : "value3",
"val1" : "value1",
"mask2" : "to be masked too",
"prop2" : {
"val1" : "value 1 again",
"mask1" : "this will also get masked"
}
}
}
This is what you get:
{
"val1": "value1",
"val2": "value2",
"mask1": "censored",
"prop1": {
"val3": "value3",
"val1": "value1",
"mask2": "censored",
"prop2": {
"val1": "value 1 again",
"mask1": "censored"
}
}
}

Default for delegate dictionary pattern

Consider this code:
switch (number)
{
case 1:
Number = (int)SmsStatusEnum.Sent;
break;
case 2:
Number = (int)SmsStatusEnum.Delivered;
break;
case 3:
Number = (int)SmsStatusEnum.Failed;
break;
default:
Number = (int)SmsStatusEnum.Failed;
break;
}
return Number;
I have a switch case that has default.So if the number is not 1,2 or 3 result to be Failed.
So i convert the code to delegate dictionary:
var statuses = new Dictionary<int, Func<SmsStatusEnum>>
{
{1,()=> SmsStatusEnum.Sent},
{2,()=> SmsStatusEnum.Delivered},
{3,()=> SmsStatusEnum.Failed},
};
How can I set default for delegate dictionary pattern?
To set a default you would just wrap the Dictionary in a function
SmsStatusEnum GetStatus(int value) {
Func<SmsStatusEnum> func;
if (!statuses.TryGetValue(value, out func)) {
// Default value
return SmsStatusEnum.Failed;
}
return func();
}
In this case though I don't quite see why you are storing a Func<SmsStatusEnum> here. Does the actual code involve computation in the Func<SmsStatusEnum> implementation? If so then this is indeed a good pattern. If not then you may want to consider just storing a Dictionary<int, SmsStatusEnum> directly
Sorry, but your solution looks bad for me. You don't need any extra dictionary to work with enums, you can create a new method and use Enum.TryParse method:
SmsStatusEnum GetStatus(int value)
{
SmsStatusEnum val;
if(Enum.TryParse<SmsStatusEnum>(value.ToString(), out val))
return val;
else
return SmsStatusEnum.Failed;
}
I go with this way:
var validStatues = new int[] {1, 3, 2};
if (!validStatues.Any(x=>x == statusId))
{
statusId = 0;
}
var statuses = new Dictionary<int, Func<SmsStatusEnum>>
{
{1,()=> SmsStatusEnum.Sent},
{2,()=> SmsStatusEnum.Delivered},
{3,()=> SmsStatusEnum.Failed},
{0,()=> SmsStatusEnum.Failed},
};

Alternative to if, else if

I have a lot of if, else if statements and I know there has to be a better way to do this but even after searching stackoverflow I'm unsure of how to do so in my particular case.
I am parsing text files (bills) and assigning the name of the service provider to a variable (txtvar.Provider) based on if certain strings appear on the bill.
This is a small sample of what I'm doing (don't laugh, I know it's messy). All in all, There are approximately 300 if, else if's.
if (txtvar.BillText.IndexOf("SWGAS.COM") > -1)
{
txtvar.Provider = "Southwest Gas";
}
else if (txtvar.BillText.IndexOf("georgiapower.com") > -1)
{
txtvar.Provider = "Georgia Power";
}
else if (txtvar.BillText.IndexOf("City of Austin") > -1)
{
txtvar.Provider = "City of Austin";
}
// And so forth for many different strings
I would like to use something like a switch statement to be more efficient and readable but I'm unsure of how I would compare the BillText. I'm looking for something like this but can't figure out how to make it work.
switch (txtvar.BillText)
{
case txtvar.BillText.IndexOf("Southwest Gas") > -1:
txtvar.Provider = "Southwest Gas";
break;
case txtvar.BillText.IndexOf("TexasGas.com") > -1:
txtvar.Provider = "Texas Gas";
break;
case txtvar.BillText.IndexOf("Southern") > -1:
txtvar.Provider = "Southern Power & Gas";
break;
}
I'm definitely open to ideas.
I would need the ability to determine the order in which the values were evaluated.
As you can imagine, when parsing for hundreds of slightly different layouts I occasionally run into the issue of not having a distinctly unique indicator as to what service provider the bill belongs to.
Why not use everything C# has to offer? The following use of anonymous types, collection initializers, implicitly typed variables, and lambda-syntax LINQ is compact, intuitive, and maintains your modified requirement that patterns be evaluated in order:
var providerMap = new[] {
new { Pattern = "SWGAS.COM" , Name = "Southwest Gas" },
new { Pattern = "georgiapower.com", Name = "Georgia Power" },
// More specific first
new { Pattern = "City of Austin" , Name = "City of Austin" },
// Then more general
new { Pattern = "Austin" , Name = "Austin Electric Company" }
// And for everything else:
new { Pattern = String.Empty , Name = "Unknown" }
};
txtVar.Provider = providerMap.First(p => txtVar.BillText.IndexOf(p.Pattern) > -1).Name;
More likely, the pairs of patterns would come from a configurable source, such as:
var providerMap =
System.IO.File.ReadLines(#"C:\some\folder\providers.psv")
.Select(line => line.Split('|'))
.Select(parts => new { Pattern = parts[0], Name = parts[1] }).ToList();
Finally, as #millimoose points out, anonymous types are less useful when passed between methods. In that case we can define a trival Provider class and use object initializers for nearly identical syntax:
class Provider {
public string Pattern { get; set; }
public string Name { get; set; }
}
var providerMap =
System.IO.File.ReadLines(#"C:\some\folder\providers.psv")
.Select(line => line.Split('|'))
.Select(parts => new Provider() { Pattern = parts[0], Name = parts[1] }).ToList();
Since you seem to need to search for the key before returning the value a Dictionary is the right way to go, but you will need to loop over it.
// dictionary to hold mappings
Dictionary<string, string> mapping = new Dictionary<string, string>();
// add your mappings here
// loop over the keys
foreach (KeyValuePair<string, string> item in mapping)
{
// return value if key found
if(txtvar.BillText.IndexOf(item.Key) > -1) {
return item.Value;
}
}
EDIT: If you wish to have control over the order in which elemnts are evaluated, use an OrderedDictionary and add the elements in the order in which you want them evaluated.
One more using LINQ and Dictionary
var mapping = new Dictionary<string, string>()
{
{ "SWGAS.COM", "Southwest Gas" },
{ "georgiapower.com", "Georgia Power" }
.
.
};
return mapping.Where(pair => txtvar.BillText.IndexOf(pair.Key) > -1)
.Select(pair => pair.Value)
.FirstOrDefault();
If we prefer empty string instead of null when no key matches we can use the ?? operator:
return mapping.Where(pair => txtvar.BillText.IndexOf(pair.Key) > -1)
.Select(pair => pair.Value)
.FirstOrDefault() ?? "";
If we should consider the dictionary contains similar strings we add an order by, alphabetically, shortest key will be first, this will pick 'SCE' before 'SCEC'
return mapping.Where(pair => txtvar.BillText.IndexOf(pair.Key) > -1)
.OrderBy(pair => pair.Key)
.Select(pair => pair.Value)
.FirstOrDefault() ?? "";
To avoid the blatant Schlemiel the Painter's approach that looping over all the keys would involve: let's use regular expressions!
// a dictionary that holds which bill text keyword maps to which provider
static Dictionary<string, string> BillTextToProvider = new Dictionary<string, string> {
{"SWGAS.COM", "Southwest Gas"},
{"georgiapower.com", "Georgia Power"}
// ...
};
// a regex that will match any of the keys of this dictionary
// i.e. any of the bill text keywords
static Regex BillTextRegex = new Regex(
string.Join("|", // to alternate between the keywords
from key in BillTextToProvider.Keys // grab the keywords
select Regex.Escape(key))); // escape any special characters in them
/// If any of the bill text keywords is found, return the corresponding provider.
/// Otherwise, return null.
string GetProvider(string billText)
{
var match = BillTextRegex.Match(billText);
if (match.Success)
// the Value of the match will be the found substring
return BillTextToProvider[match.Value];
else return null;
}
// Your original code now reduces to:
var provider = GetProvider(txtvar.BillText);
// the if is be unnecessary if txtvar.Provider should be null in case it can't be
// determined
if (provider != null)
txtvar.Provider = provider;
Making this case-insensitive is a trivial exercise for the reader.
All that said, this does not even pretend to impose an order on which keywords to look for first - it will find the match that's located earliest in the string. (And then the one that occurs first in the RE.) You do however mention that you're searching through largeish texts; if .NET's RE implementation is at all good this should perform considerably better than 200 naive string searches. (By only making one pass through the string, and maybe a little by merging common prefixes in the compiled RE.)
If ordering is important to you, you might want to consider looking for an implementation of a better string search algorithm than .NET uses. (Like a variant of Boyer-Moore.)
What you want is a Dictionary:
Dictionary<string, string> mapping = new Dictionary<string, string>();
mapping["SWGAS.COM"] = "Southwest Gas";
mapping["foo"] = "bar";
... as many as you need, maybe read from a file ...
Then just:
return mapping[inputString];
Done.
One way of doing it (other answers show very valid options):
void Main()
{
string input = "georgiapower.com";
string output = null;
// an array of string arrays...an array of Tuples would also work,
// or a List<T> with any two-member type, etc.
var search = new []{
new []{ "SWGAS.COM", "Southwest Gas"},
new []{ "georgiapower.com", "Georgia Power"},
new []{ "City of Austin", "City of Austin"}
};
for( int i = 0; i < search.Length; i++ ){
// more complex search logic could go here (e.g. a regex)
if( input.IndexOf( search[i][0] ) > -1 ){
output = search[i][1];
break;
}
}
// (optional) check that a valid result was found.
if( output == null ){
throw new InvalidOperationException( "A match was not found." );
}
// Assign the result, output it, etc.
Console.WriteLine( output );
}
The main thing to take out of this exercise is that creating a giant switch or if/else structure is not the best way to do it.
There are several approaches to do this, but for the reason of simplicity, conditional operator may be a choice:
Func<String, bool> contains=x => {
return txtvar.BillText.IndexOf(x)>-1;
};
txtvar.Provider=
contains("SWGAS.COM")?"Southwest Gas":
contains("georgiapower.com")?"Georgia Power":
contains("City of Austin")?"City of Austin":
// more statements go here
// if none of these matched, txtvar.Provider is assigned to itself
txtvar.Provider;
Note the result is according to the more preceded condition which is met, so if txtvar.BillText="City of Austin georgiapower.com"; then the result would be "Georgia Power".
you can use dictionary.
Dictionary<string, string> textValue = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> textKey in textValue)
{
if(txtvar.BillText.IndexOf(textKey.Key) > -1)
return textKey.Value;
}

Using strings instead of enums?

Is it common place to use a string for comparison as opposed to an enum?
I am aware about your context, but as a first step you can just refactor this way:
Step 1
if (typeOfObject == "UAV")
{
DoSomeWork(_stkObjectRootToIsolateForUavs);
}
else if (typeOfObject == "Entity")
{
DoSomeWork(_stkObjectRootToIsolateForEntities);
}
private void DoSomeWork(IAgStkObject agStkObject)
{
IAgStkObject stkObject = agStkObject.CurrentScenario.Children[stkObjectName];
IAgDataProviderGroup group = (IAgDataProviderGroup)stkUavObject.DataProviders["Heading"];
IAgDataProvider provider = (IAgDataProvider)group.Group["Fixed"];
IAgDrResult result = ((IAgDataPrvTimeVar)provider).ExecSingle(_stkObjectRootToIsolateForUavs.CurrentTime);
stkObjectHeadingAndVelocity[0] = (double)result.DataSets[1].GetValues().GetValue(0);
stkObjectHeadingAndVelocity[1] = (double)result.DataSets[4].GetValues().GetValue(0);
}
Then consider replasing if's with switch:
Step 2
switch (typeOfObject)
{
case "UAV":
DoSomeWork(_stkObjectRootToIsolateForUavs);
break;
case "Entity":
DoSomeWork(_stkObjectRootToIsolateForEntities);
break;
default:
throw new NotImplementedException():
}
This can be even better when using enums.
At the very least, the strings should be declared as constants (or perhaps readonly fields) somewhere, instead of spread out through the code. However, this looks like the schoolbook example for when to use an enum.
public enum ObjectType
{
UAV,
Entity,
// and so on
}
To add to #Restuta's answer, I'd use a
IDictionary<MyEnumifiedString, Action<IAgStkObject>>
to get rid of that if.
I'd agree with #Frederik that this seems a perfect case for using enums, but it could be that the only thing you can get out of the application is a string. In which case your example is perfectly OK.
Oh yes - and make sure you have the string constants defined in one place, preferably a config file so that if they change the other application you don't have to recompile yours.
Regarding your first question I will always use a defined type to store the strings simply to have one location for change if needed.
So for your example i would have the following
public sealed class RootTypes
{
public const string Entity = "entity";
public const string UAV = "uav";
}
Your code then updates to this
typeOfObject = typeOfObject.ToLower();
if (typeOfObject == RootTypes.UAV)
{
stkUavObject = _stkObjectRootToIsolateForUavs.CurrentScenario.Children[stkObjectName];
var group = (IAgDataProviderGroup) stkUavObject.DataProviders["Heading"];
var provider = (IAgDataProvider) group.Group["Fixed"];
IAgDrResult result = ((IAgDataPrvTimeVar) provider).ExecSingle(_stkObjectRootToIsolateForUavs.CurrentTime);
stkObjectHeadingAndVelocity[0] = (double) result.DataSets[1].GetValues().GetValue(0);
stkObjectHeadingAndVelocity[1] = (double) result.DataSets[4].GetValues().GetValue(0);
}
else if (typeOfObject == RootTypes.Entity)
{
IAgStkObject stkEntityObject = _stkObjectRootToIsolateForEntities.CurrentScenario.Children[stkObjectName];
var group = (IAgDataProviderGroup) stkEntityObject.DataProviders["Heading"];
var provider = (IAgDataProvider) group.Group["Fixed"];
IAgDrResult result = ((IAgDataPrvTimeVar) provider).ExecSingle(_stkObjectRootToIsolateForEntities.CurrentTime);
stkObjectHeadingAndVelocity[0] = (double) result.DataSets[1].GetValues().GetValue(0);
stkObjectHeadingAndVelocity[1] = (double) result.DataSets[4].GetValues().GetValue(0);
}
The issue of code redundancy has been anserwed by Restuta
Use enums with bit flags:
[Flags]
public enum MyFlags
{
SomeFlag = 0x1, // 001
OtherFlag = 0x2,// 010
ThirdFlag = 0x4 // 100
}
var firstObject = MyFlags.SomeFlag;
var secondObject = MyFlags.SomeFlag | MyFlags.OtherFlag;
if(((int)secondObject & MyFlags.SomeFlag) != 0)
{
// true
}
if(((int)secondObject & MyFlags.OtherFlag) != 0)
{
// true
}
if(((int)firstObject & MyFlags.SomeFlag) != 0)
{
// true
}
if(((int)firstObject & MyFlags.OtherFlag) != 0)
{
// false
}
This article would be helpful.

Validation - looking for certain combinations of values

I'm doing some validation where I need to check for certain combinations between two values. For example, if string1 is "fruit", valid values for string2 are "apple", "banana" and "pear". Currently, I'm doing this:
switch(string1)
{
case "fruit":
if(string2 != "apple" && string2 != "banana")
{
return false;
}
break;
case "meat":
if(string2 != "beef" && string2 != "pork")
{
return false;
}
default:
return true;
break;
}
This is really two questions. The first is, is there any good way to do something more like this:
switch(string1)
{
case "fruit":
if(string2 NOT IN ("apple", "banana"))
{
return true;
}
break;
case "meat":
if(string2 NOT IN ("beef", "pork"))
{
return false;
}
default:
return true;
break;
}
The second part of this question is likely what will get answered first: is there a better/best way to do this? I'm not the most amazing coder in the world and this is the first "off the top of my head" solution, so I'm certainly open to better ones. Thanks!
A variation on Nick's answer. Create two lists and use the contains method against them.
public List<string> Fruit = new List<string>{"apple", "banana"};
public List<string> Meat = new List<string>{"beef", "pork"};
switch (string1)
{
case "fruit":
return Fruit.Contains(string2);
case "meat":
return Meat.Contains(string2);
}
Yeah, there's a better way. You want to create a map, which associates your "category" ("fruit") with a string List of your elements ("apple", "banana", etc.). Then you want to look up your "string1" in your example above from the map and see if your associated string List Contains() your "string2".
This makes it entirely data-driven, and leverages the built-in abilities of the Collections more successfully.
Here is a way using Linq:
Dictionary<string, IList<string>> validValues = new Dictionary<string, IList<string>>()
{
{ "fruit", new List<string>() { "apple", "banana" } },
{ "meat", new List<string>() { "pork", "beef" } }
};
if (validValues.FirstOrDefault(x => x.Key == string1 && x.Value.Contains(string2)).Value != null)
{
return true;
}
return false;
You can shorten your cases down to:
switch(string1)
{
case "fruit":
return new[] { "apple", "banana" }.Contains(string2);
case "meat":
return new[] { "beef", "pork" }.Contains(string2);
default:
return true;
break;
}
I think style is, to a large degree, dependent upon personal taste. This is my taste...I think it's easy to add a new value in there with the array style, with as little overhead (I believe, someone feel free to correct me) that you can get with an array/collection style of "if-in" type check.
You could do something like this:
Dictionary<string, string> map = new Dictionary<string, string>();
map.add("banana", "fruit");
map.add("apple", "fruit");
map.add("pear", "fruit");
map.add("beef", "meat");
map.add("pork", "meat");
if(map[string2] == string1)
return true;

Categories