When to use FOR-CASE (Foreach/switch in C#)? - c#

I've found what seems to be the C# equivalent of a FOR-CASE structure in a project I'm working on:
foreach (string param in params.Split(';'))
{
string[] parts = param.Split('=');
string key = parts[0].Trim().ToLower();
string value = parts[1].Trim();
switch (key)
{
case "param1": this.param1 = value; break;
case "param2": this.param2 = value; break;
case "param3": this.param3 = value; break;
case "param4": this.param4 = value; break;
default: break;
}
}
(Variable names changed to protect the guilty.)
How would you implement this code?

I don't think the code in your question is anything like the code you linked to....
The code in the question looks like something I might do if I wrote a command line tool.
Am I stupid for not seeing whats wrong with the code in the question?
An alternative is to use reflection to fill parameter value variables. I've done it that ways sometimes too.
BTW: I once wrote a program in a script language that had switch as the only flow control mechanism and no gosub/return. The code in my program was structured a bit like the one you linked to. A massive switch on a sort of instruction pointer variable that got reassigned at the end of every case and an almost infinite loop around the switch. It got the job done.

I see you that you already have multiple fields in your class that you use to hold the variables. In that case, what you are doing is fine.
Otherwise, you can have 1 HashTable (maybe add in the C# indexor as a twist) to hold all of them, and your loop will end up like this:
foreach (string param in params.Split(';'))
{
string[] parts = param.Split('=');
string key = parts[0].Trim().ToLower();
string value = parts[1].Trim();
MyHashTable[key] = value;
}
The problem with this approach is that you should only have 1 type of value. For example, if your param list can contain both string and int types, it makes the code messier, especially you need to perform error checking and validation and stuff.
I personally would stick with what you already have.

You could use reflection for this:
Type t = this.GetType();
foreach (string param in params.Split(';'))
{
string[] parts = param.Split('=');
string key = parts[0].Trim().ToLower();
string value = parts[1].Trim();
t.GetProperty(key).SetValue(this, value, null);
}

For what it's worth, the WTF article was a WTF because its outer loop was completely useless, as noted in the article - it was just as easy, and more direct, just to set an index variable directly than to loop and test it.

Not sure if I understand either but it sounds like you're complicating yourself. Don't reinvent the wheel, use BCL classes as much as you can, these classes are proven to work efficiently and save you lots of time. Sounds like you could implement it with some sort of Dictionary<,> along with, like Guge suggested, Reflection.

I actually think the OP's code is fine. It's not perfect -- there might be simpler or cleaner ways to do it, but it effectively allows for readable mappings between member/property names and input-parameter names. It leaves your properties strongly typed (unlike the hashmap/dictionary solutions, unless your class has only one type for all its properties...) and gives you one fairly-obvious place to fix or add mappings.

Or Regex:
string parms = "param1=1;param2=2;param3=3";
string[] parmArr = parms.Split(';');
string parm1 = Regex.Replace(parmArr[0], "param1=", "");
string parm2 = Regex.Replace(parmArr[1], "param2=", "");
string parm3 = Regex.Replace(parmArr[2], "param3=", "");

Related

The best way to transfer information from class to class in c#

I got question, what is the best way to transfer information from class to class. I mean, I tried with return strings, where I have 3 items in listbox and they are named e.g. Easy Normal and Hard and then strings are named as items. It didn't work well for me, because than I loaded method, he returned me the string, but I cant use this in other class. Im doing it like this, by creating first in the first class:
if(listBox1.SelectedItem.ToString() == "Easy")
{
return "Easy";
}
And then, in second class:
if(class.string1() == "Easy")
{
Do something.
}
It doesn't work. Do you guys can maybe help me? Or this question is too newbie, and I have to learn and search more.
I prefer to utilize enumerations rather than "magic strings". They are type safe and less error-proned. You can convert a string to an enum as well which lends itself well to your problem:
public enum DifficultyEnum {
NULL,
Easy,
Medium,
Hard
}
public DifficultyEnum GetDifficulty() {
var difficulty = DifficultyEnum.NULL;
var selItem = listBox1.SelectedItem.ToString();
Enum.TryParse<DifficultyEnum>(selItem, out difficulty);
return difficulty;
}
Then in your other class:
swtich (classInstance.GetDifficulty()) {
case Easy:
break;
case Medium:
break;
case Hard:
break;
case NULL: /*Hopefully you don't get here but be defensive and expect that somehow they'll manage to do so =P */
break;
}
Edit:
This is an issue of preference but you can also make the GetDifficulty() into a property instead like so:
public DifficultyEnum Difficulty {
get {
var difficulty = DifficultyEnum.NULL;
var selItem = listBox1.SelectedItem.ToString();
Enum.TryParse<DifficultyEnum>(selItem, out difficulty);
return difficulty;
}
}
You seem to be asking a few different questions here.
How you transfer information between classes depends on the type of classes you are using and the type of data you want to transfer. The simplest way to share data is probably to have a method that provides the data (either as return values, reference parameters, or a class returned that contains the data).
Beyond that, you need to be more specific about what "doesn't work" means. I can see it would work assuming it's set up correctly. However, it's not very efficient because comparing strings requires comparing each character in the string. It would make more sense to define an enum.
public enum Difficulty
{
Easy,
Normal,
Hard
}
And compare it like this:
if(classInstance.Difficulty == Difficulty.Easy)
{
// Do something.
}
Of course, your class will need to determine which list item is selected and convert it to an enum.

can I use a c# switch here?

i would like to refactor this code. Maybe if possible by using a switch? Or is it the same in terms of performance?
string rawUrl = context.Request.RawUrl ?? string.Empty;
if (rawUrl.Contains("mypage.aspx"))
{
}
if (rawUrl.Contains("mypage2.aspx"))
{
}
etc..
Not directly, since you want a "contains" relation, rather than an exact equality.
However, if you so desire, you could do it indirectly by attempting to parse the page name out of what I assume would be the URL, storing it in a separate String variable, and switching on that String.
For example:
// Get the URL from some external source (wherever you're already getting it from)
String rawUrl = "http://www.example.com/foo/bar.aspx";
// Means of parsing will be dependent on the format in which you expect the URL.
String page = rawUrl.Substring(rawUrl.LastIndexOf("/") + 1);
switch (page) {
case "bar.aspx":
// Do stuff
break;
case "foo.aspx":
// Do stuff
break;
}
And, of course, please take this parsing methodology with a grain of salt; this example was to show you that it is possible, but note that this method of parsing could potentially throw an exception in a number of cases, but I've omitted those checks for the sake of brevity.
Switch Cases must be a constant value. You're best bet there is to use if/else like so:
string rawUrl = context.Request.RawUrl ?? string.Empty;
if (rawUrl.Contains("mypage.aspx"))
{
//code
}
else if (rawUrl.Contains("mypage2.aspx"))
{
//more code
}
If you're concerned about performance (which is good!) then the else is the way to go. While not using an else will have the same functionality, by adding the else, you're telling the code to not process any of the other if conditions. So 10 if statements will result in 10 if conditions being processed not matter what, while 10 if/else statements might result in 10, or it might only result in 1.
EDIT:
Thought about this some, and I noticed you were using the context object. If you really wanted a switch statement, you can do the following:
string page = context.Request.Url.Segments.Last();
switch(page)
{
case "mypage.aspx":
//code
break;
case "mypage2.aspx":
//more code
break;
}
Not for a contains.
Try to isolate page name alone and you can could do it.
switch(pageName)
{
case "mypage.aspx";
break;
case "mypage2.aspx";
break;
}
I think it is better to use a Dictionary.
First, extract the file name from the raw url.
Then, use a Dictionary<string,TValue>.
If the actions to the pages are almost the same, set TValue to the type of the data associated with the pages.
If the actions are very different, set TValue to a delegate type such as Action.

String insertion problem in c#

I am trying to insert a string at a position for C# string, its failing
here is the snippet.
if(strCellContent.Contains("<"))
{
int pos = strCellContent.IndexOf("<");
strCellContent.Insert(pos,"<");
}
please tell me the solution
The return value contains the new string that you desire.
strCellContent = strCellContent.Insert(pos,"<");
Gunner and Rhapsody have given correct changes, but it's worth knowing why your original attempt failed. The String type is immutable - once you've got a string, you can't change its contents. All the methods which look like they're changing it actually just return a new value. So for example, if you have:
string x = "foo";
string y = x.Replace("o", "e");
the string x refers to will still contain the characters "foo"... but the string y refers to will contain the characters "fee".
This affects all uses of strings, not just the particular situation you're looking at now (which would definitely be better handled using Replace, or even better still a library call which knows how to do all the escaping you need).
I think you might be better of with a Replace instead of an Insert:
strCellContent = strCellContent.Replace("<", "<");
Maybe doing Server.HtmlEncode() is even better:
strCellContent = Server.HtmlEncode(strCellContent);
When I look at your code I think you want to do a replace, but try this:
if(strCellContent.Contains("<"))
{
int pos = strCellContent.IndexOf("<");
strCellContent = strCellContent.Insert(pos,"<");
}
.Contains is not a good idea here, because you need to know the position. This solution will be more efficient.
int pos = strCellContent.IndexOf("<");
if (pos >= 0) //that means the string Contains("<")
{
strCellContent = strCellContent.Insert(pos,"<"); //string is immutable
}
As others have explained with the code, I will add that
The value of the String object is the
content of the sequential collection,
and that value is immutable (that is,
it is read-only).
For more information about the immutability of strings, see the Immutability and the StringBuilder Class section.
from: http://msdn.microsoft.com/en-us/library/system.string.aspx

Refactoring switch statement for Data to different types of data

My mission is to refactor a switch statement that was poorly written (it makes the cyclomatic complexity spike). In short, there is a class that parses a file for various values.
class foo
{
//a sampling of the fields. Each have their appropriate property
private string _name;
private short _location;
private int _lineNumber;
private List<string> _siblings;
internal foo (StreamReader reader)
{
_siblings = new List<string>()
while (!reader.EndofFile)
{
switch (reader.ReadLine())
{
case "Name":
_name = reader.ReadLine();
break;
case "Location":
_location = short.Parse(reader.ReadLine());
break;
case "Line Number":
_lineNumber = int.Parse(reader.ReadLine());
break;
case "Brother":
case "Sister":
_siblings.Add(reader.ReadLine());
break;
//etc
}
}
}
//Other methods and such
}
I have read up on the topic and while there seems to be plenty of help, it all seems to be pointing at the Strategy design pattern, which (I believe) would overkill my problem. In my project, there are multiple classes like this, with some of them having upwards of 25 case statements (so kudos to those who can come up with an idea of and interface or abstract class)
I have thought about using a Dictionary<String, TValue> as described by John Sonmez, but then what would TValue be?
Any help would be greatly appreciated.
First of all, reader.ReadLine() is really not part of the switch statement here so I would advise that you just read lines two by two and pass to another class to handle. (first line seems to define what it is and second has the value).
Your handler will contain the action. If you do not want to use Strategy - which is easy and perhaps you should - have the value of the Dictionary as delegates each implementing a strategy:
Dictionary<string, Action<string>> dic = new Dictionary<string, Action<string>>();
dic.Add("Father", ((x)=> // somthing);
dic.Add("Brother", ((x)=> // somthing);
dic.Add("Sister", ((x)=> // somthing);
Two options.
If there was a convention that the data read from the line matched the name of a property, you could by convention populate the property via reflection. Alternatively, you could use an attribute on the property that corresponded to the expected value you would read from the file.
Hope that helps or at least points you in the right direction :)

Map Literals to Object Properties/Values

For eg, my input XML is look like this.
<root>
<myelemt>
<input type="variable">
<variable>STARTDATE</variable>
<variable>CUSTOMERNAME</variable>
</input>
</myelemt>
</root>
it is deserialized and loaded into the object MyXmlElemtObj
in my code i have written like this,
if(MyXmlElemtObj.input.variable.ToUpper() == "STARTDATE")
ProcessObjectB(ObjectA.OrderDate);
if(MyXmlElemtObj.input.variable.ToUpper() == "CUSTOMERNAME")
ProcessObjectB(ObjectC.UserName);
Here I am mapping those input literals to some objects value.
The one thing that scares me is seeing some ** hard-coded literals** all over my code.
Instead i would like to write something like ProcessObjectB(Common.GetMappedvalue(MyXmlElemtObj.input.variable));
Is there a way to isolate this mapping thing to common class, where i will predefine
which literal is mapped to which values. The problem is the values are of objects created at the run time.
If my question is making sense then So how do i achieve this?
I think i have given all the necessary details. if anything is missing please metnion. Thx Much.
The question is worded a little confusing, but from what I gather you are just looking for an intermediary class to perform the mapping of an input variable to a string. You mention that you don't want there to be hard-coded string literals; The logical remedy here would be to declare a series of constants for them (perhaps at the top of your intermediary mapping class?).
public class Common
{
public const string STARTDATE = "STARTDATE";
public const string CUSTOMERNAME = "CUSTOMERNAME";
public static string GetMappedValue(string inputVariable)
{
string mappedTo = null;
switch(inputVariable)
{
case "abc":
mappedTo = SOME_OTHER_CONSTANT_HERE; //map it
break;
case "xyz":
mappedTo = FOO;
break;
//etc etc...
}
return mappedTo;
}

Categories

Resources