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;
}
Related
I've the following class
public static class Translation
{
public enum LanguageCultureName
{
enGB,
zhCN
};
public static string Get(LanguageCultureName languageCultureName, string sValue)
{
if (languageCultureName == LanguageCultureName.enGB)
{
return sValue;
}
else
{
//get translated string
return ....
}
}
}
Basically I'm looking to call the method like
Is it preferable to put an inline If statement around the method call like;
LanguageCultureName languageCultureName = LanguageCultureName.zhCN;
string sTranslation = languageCultureName == LanguageCultureName.enGB ? "My String to translate" : Translation.Get(languageCultureName, "My String to translate");
,or just call it, and if it is enGB return the passed string like
LanguageCultureName languageCultureName = LanguageCultureName.zhCN;
string sTranslation = Translation.Get(languageCultureName, "My String to translate");
Are there any performance reasons for this, or is it personal preference ?
This is abstraction that should happen inside the Get method, not inlined.
LanguageCultureName languageCultureName = LanguageCultureName.zhCN;
string sTranslation = Translation.Get(languageCultureName, "My String");
I should also note that having the enGB strings hardcoded is not a good practice. You should move both the enGB and zhCN strings to external resources files (e.g. .resx).
I would go with the second one. There will be very little performance impact but it is more readable.
The way I understand your code is that you want check if the culture is already in English or not and return the standard string if it is instead of translating it. In order for this to make a performance impact you have to take a few aspects in account
How often do you expect the culture to be in English?
How intensive is the translating operation?
Can you pass around a non-english string as input?
Each of these remarks will have influence over your eventual design. You seem to be entertaining the thought of removing the english if altogether and replace it with a ternary statement, aka: removing an if and adding an if in the wrong place.
And having considered all that: if your validation whether or not it's an english culture is the first statement inside your method, there will never be a notable difference between that and putting it outside in the ternary statement.
Let's not forget one of the ten comandments:
We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
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.
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 :)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
There has been talk of Enums in general violating Clean Code-principles, so I'm looking for people's favorite Enum anti-patterns and alternative solutions for these.
For example I've seen code like this:
switch(enumValue) {
case myEnum.Value1:
// ...
break;
case myEnum.Value2:
// ...
break;
}
It's one step better than switch-statements with magic strings, but this probably could have been solved better with a factory, a container or other pattern.
Or even old-school code like this:
if(enumValue == myEnum.Value1) {
// ...
} else if (enumValue == myEnum.Value2) {
// ...
}
What other anti-patterns and better implementations have you experienced with enums?
I think Enums are quite useful. I've written a few extensions for Enum that have added even more value to its use
First, there's the Description extension method
public static class EnumExtensions
{
public static string Description(this Enum value)
{
var entries = value.ToString().Split(ENUM_SEPERATOR_CHARACTER);
var description = new string[entries.Length];
for (var i = 0; i < entries.Length; i++)
{
var fieldInfo = value.GetType().GetField(entries[i].Trim());
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
description[i] = (attributes.Length > 0) ? attributes[0].Description : entries[i].Trim();
}
return String.Join(", ", description);
}
private const char ENUM_SEPERATOR_CHARACTER = ',';
}
This will allow me to define en enum like this:
public enum MeasurementUnitType
{
[Description("px")]
Pixels = 0,
[Description("em")]
Em = 1,
[Description("%")]
Percent = 2,
[Description("pt")]
Points = 3
}
And get the label by doing this: var myLabel = rectangle.widthunit.Description() (eliminating any need for a switch statement).
This will btw return "px" if rectangle.widthunit = MeasurementUnitType.Pixels or it will return "px,em" if rectangle.widthunit = MeasurementUnitType.Pixels | MeasurementUnitType.Em.
Then, there is a
public static IEnumerable<int> GetIntBasedEnumMembers(Type #enum)
{
foreach (FieldInfo fi in #enum.GetFields(BindingFlags.Public | BindingFlags.Static))
yield return (int)fi.GetRawConstantValue();
}
Which will let me traverse any enum with int based values and return the int values themselves.
I find these to be very useful in an allready useful concept.
It all depends what your trying to do with the enum.
If you are trying to stop your developers from passing magic numbers into your operations and you want to keep the data referential integrity intact with your DB then, YES! Use T4-Templates (using your ORM) to go to your MeasurementUnitTypes table and generate a enum with the ID, Name and Description columns matching the enum’ int, Enum_Name and Description Attribute (nice approach for additional field\data to enum #danijels) as suggested above. If you add a new Measurement Type to your MeasurementUnitTypes table you can just right click and run the T4-Template and the enum code is generated for that new row added in the table. I don’t like hard-coded data in my application that doesnt link to my DB hence the mention of the T4-Template approach. It is not extensible otherwise...what if some other external system wants to retrieve our Measurement Criteria used in our system, then it is hard-coded in the system and you can't expose it to the client via a service. That left there.
If the purpose is not data related and you have some logic assigned to a specific enum then NO! this violates the SOLID (Open close principle) as you would somewhere in your application apply a switch or bunch of Ifs to action the logic per enum, ALSO if you did it REALLY bad these switches or Ifs are all over the show....good luck adding a new enum... so it is not open for extension and closed for modification as you need to modify existing code, as per the SOLID principle.
If your choice is 2 then I suggest then to replace your enum with the following using the example from #danijels comment:
public interface IMeasurementUnitType
{
int ID { get; }
string Description { get; }
// Just added to simulate a action needed in the system
string GetPrintMessage(int size);
}
The above code defines the interface (code contract) that each measurement should adhere to. Now lets define Percentage and Pixel measurement :
public class PixelsMeasurementUnitType : IMeasurementUnitType
{
public int ID => 1;
public string Description => "Pixel";
public string GetPrintMessage(int size)
{
return $"This is a {Description} Measurement that is equal to {size} pixels of the total screen size";
}
}
public class PercentMeasurementUnitType : IMeasurementUnitType
{
public int ID => 2;
public string Description => "Persentage";
public string GetPrintMessage(int size)
{
return $"This is a {Description} Measurement that is equal to {size} persent of total screen size (100)";
}
}
So wee have defined two types, we would use them in code as follows:
var listOfMeasurmentTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => typeof(IMeasurementUnitType).IsAssignableFrom(p)
&& !p.IsInterface)
.ToList();
Here we grab all the TYPES that extends the IMeasurementUnitType interface and NOT the interface itself. Now we can use the Activator to create instances of the classes to populate our UI controls:
public IEnumerable<IMeasurementUnitType> GetInstantiatedClassesFromTypes(List<Type> types)
{
foreach (var type in types)
{
yield return (IMeasurementUnitType)Activator.CreateInstance(type);
}
}
You can change the code above to be generic for any type, AND NOW life happens and the client give a new measuring unit type called Point as a new requirement, I don't need to CHANGE ANY code, just add the new type (extend the code NOT modify). The new type will automatically be picked up in the application.
public class PointMeasurementUnitType : IMeasurementUnitType
{
public int ID => 3;
public string Description => "Point";
public string GetPrintMessage(int size)
{
return $"This is a {Description} Measurement that is equal to {size} points of total screen size";
}
}
a Good idea would be to cache your types for performance benefits upon starting your application or try and use a DI container of your choice.
Also, one can argue that somewhere in you application you would need to distinguish between types and I agree, however you want to keep apples with apples. So try as far as possible to apply the same principle used for this types. If this type is used in some sort of Graphics processor (for example) class then have a IGraphicsProcessor and have your concrete classes that differentiate between these types for example PersentageAndPixelGraphicsProcessor (that extends from IGraphicsProcessor) or if it distinguishes only one type call it PersentageGraphicsProcessor.
Sorry for the HUGE SA but I really like enum's however I feel when you trying to separate logic using a enums it is a STRONG anti-pattern.
comments welcome,
This isn't an answer, as much as contributing to a list of Enum anti-patterns.
During a code review this morning, I ran into a case similar to the following, all in the same class.
Two cases:
Before drinking
After drinking
..
public enum ListEnum
{
CategoryOne,
CategoryTwo,
CategoryThree,
CategoryFour
}
public class UIELementType
{
public const string FactoryDomain = "FactoryDomain";
public const string Attributes = "Attributes";
}
Using enums in not anti-pattern. In some books about refactoring this code is used to demonstrate how to replace it with polymorphism. It would be OK when you overuse enums in code.
I see having two switch statements as a symptom of non-OO design as explained further in this answer.
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=", "");