Converting code using generics - c#

I've following code that uses the passed Object and acts on it after determining its type. My question is that if I convert it to use generics, will I get any performance advantage since I'd still have to determine the type of T before I act upon it? Will I save ticks on boxing/unboxing?
private void BindOptionFields(Object obj, String selectedValue, int dataLanguageID)
{
String typ = obj.GetType().Name;
switch(typ.ToLower())
{
case "ratingscaleitem":
SetRatingScale((Common.RatingScaleItem)obj, dataLanguageID, selectedValue);
break;
case "taskstatus":
text = ((TaskStatus)obj).TaskName;
optionValue = ((TaskStatus)obj).StateID.ToString();
break;
case "planlite":
text = ((XYZ.ABC.PlanLite)obj).PlanName;
optionValue = ((XYZ.ABC.PlanLite)obj).Id.ToString();
break;
case "datarow":
text = ((DataRow)obj)["TextColumn"].ToString();
optionValue = ((DataRow)obj)["KeyColumn"].ToString();
break;
default:
break;
}
if (optionValue == selectedValue)
{
selected = true;
}
}
Note: I've 3 constructors in my class that receive an ArrayList of 20 different types (similar types in ArrayList for a particular call). I loop through the arraylist and call this BindOptionFields() so if I've to write overloaded methods, I'll have to overload my constructors for 20 cases each. Can someone suggest a less tedious solution that would be fast as well?

You're misunderstanding generics.
If you convert this method to a generic method, the caller will need to specify the generic parameter at compile-time.
At that point, you can just use a normal set of overloaded methods.

Would it not be better to add a BindOptionField method (perhaps as part of an Interface e.g. IOptionFieldBindable) to the types you're switching on here?
The TaskStatus, PlanLite, and DataRow Types are good candidates particularly, since they're each providing a different way to set the same two values. That way, you could just call
(obj as IOptionFieldBindable).BindOptionField(text, optionValue);
Your solution would also be less Stringly Typed :)

Related

How do you return different lists based on an enum?

I've seen that people have asked similar questions but they're normally using complex types and resolve to use interfaces instead. What I would like to do is pass back either list, list or list depending on an enum. Something like this:
private IList<T> GetValueFromType<T>(MyData data)
{
switch (data.SomeType)
{
case MyType.Percent:
var PercentValues = new List<double>();
PercentValues.Add(data.CompAPercentage);
PercentValues.Add(data.CompBPercentage);
return (T)PercentValues;
case MyType.Money:
var MoneyValues = new List<decimal>();
MoneyValues.Add(data.CompAMoney);
MoneyValues.Add(data.CompBMoney);
return (T)MoneyValues;
case MyType.Months:
var MonthValues = new List<int>();
MonthValues.Add(data.CompAMonth);
MonthValues.Add(data.CompBMonth);
return (T)MonthValues;
}
}
This shows an error on all 3 return statements saying the type can't be converted to 'T'. Is this possible / advised or is this a code smell?
You basically can't do this.
It is possible to circumvent the static type-checking as Mike's answer says in order to make GetValueFromType<T> compile, but how will you invoke it? Your calling code will need to specify T, eg.
var myValue = GetValueFromType<int>(myData)
because there's no way to infer T from the call itself, and when the method tries to return a list which doesn't match your choice of T you'll get an InvalidCastException. Given that you need to interrogate MyData to find out how to call this method safely, you might as well have the switch in the calling code.
This is somewhat dangerous because it loses some of the power of static type checking and is easy for callers to get wrong. The compiler will flag it. You may need to insert an (object) cast to tell the compiler you really want to make the cast:
return (IList<T>) (object) MonthValues;

Why typeof(int).ToString() is not constant?

I'm trying to do this:
const string intType = typeof(int).ToString();
switch (typeof(MyT).ToString())
{
case intType:
{
return "int";
break;
}
...
}
But compiler says:
error CS0133: The expression being assigned to 'intType' must be constant
As I know, typeof operator works at compile-time. So, what's wrong?
As I know, typeof operator works at compile-time.
You don't know that because knowledge has to be true. Where did you get the idea that typeof is executed at compile time? It produces a non-constant object. And then there is no guarantee that ToString doesn't produce a different string every time it runs, so it cannot be treated as a constant either.
So, what's wrong?
You're reasoning from a false belief.
The C# specification clearly describes the conditions that must be met for an expression to be a compile-time constant. Those conditions include the expression not containing any typeof operator or method call.
But there are far bigger problems here. I assume that MyT is a generic type parameter, which means you are attempting to switch on the value of a generic type parameter. That is almost always the wrong thing to do.
What are you really trying to do? What problem are you really trying to solve? Because this code you've shown so far indicates that you're going down an unproductive path to solve whatever the real problem is.
I think, it is quite obvious, what he wants to achieve:
He wants to check for type equality in a switch-case instead of via if-elseif. And to be honest, why not? But how can he achieve this?
First option: Wait for C# 7.0. Yeah, shit like this is possible in the future!
Second option: Use strings. But the case strings need to be constant. So what about the wonderful nameof?
I just tried this "beauty" and it works, so maybe this solves your problem:
switch (typeof(Int32).Name)
{
case nameof(Int32):
Console.WriteLine("It's an Int32!");
break;
case nameof(Double):
Console.WriteLine("It's a Double");
break;
}
The only way to compare type MyT with known types is by checking their Type objects for equality. This can be done as follows:
if (typeof(MyT) == typeof(int)) return "int";
if (typeof(MyT) == typeof(decimal)) return "decimal";
// etc...
You cannot use this approach in a switch because (at the moment) a switch requires that the item being checked is of a simple type:
switch (typeof(T)) // Compile error: "switch expression or case label must be a bool,
// char, string, integral, enum, or corresponding nullable type"
{
case typeof(int): return "int";
case typeof(decimal): return "decimal";
// ...
}
Also, as others already said, checking types in this way almost always means that your approach can be improved by applying different object oriented principles.
E.g. instead of MyMethod<MyT>(MyT item) with type checks for MyT, consider making MyMethod(int item), MyMethod(decimal item) etc.
If you are just trying to get a string describing the type of object, you just need to call .GetType() instead.
For example, the following is a small function that will return the string name of the object type.
static string GetTypeString(object obj)
{
return obj.GetType().FullName;
}
This will return to the full path to the object. In int's case, it will return System.Int32. If you only want the Int32 part, use GetType().Name instead.
Also, you don't need to have a break; in a switch if you have a return;
If you have specific code that needs to be run for some types, or a specific string you want to return, you can use a string on the values returned by the above. For example:
static string GetSimpleType(object obj)
{
var stringRepresentation = GetTypeString(obj);
switch (stringRepresentation)
{
case "System.Int64":
case "System.Int32":
return "int";
default:
return stringRepresentation;
}
}
default is a catch all in switch statements for everything that does not have a case. Think of it like an else.
In the above example, we return the same value for int, Int32, and Int64. Case labels can fall through to other case labels if they are empty.
You can find all the values you need to write a switch for by running a simple script, and hard code the string values since they will always be the same for the same types. If the string is different, then the type is different.
Finally, if you are comparing types, if and if else works better:
static string GetSimpleType(object obj)
{
if (obj.GetType() == typeof(int))
{
return "int";
}
return obj.GetType().ToString();
}

Use dynamic keys in keydownevent

I'm doing a little C# program, but it is configurable. Properties.Settings.Default.foobar is equal to F3, but that is subject to change. Originally it'd be this way:
case Keys.F3:
//dostuff
break;
But I need Properties.Settings.Default.foobar in place of F3, since it's a setting and thus subject to change.
case Keys.Properties.Settings.Default.foobar:
Obviously doesn't work, nor does putting it in parenthesis, so I'm not sure. I'm clearly new to C#, so any help?
The program uses unfocused hotkeys, but these keys are user configurable, so I can't have any sort of constant/static for a case, right?
case Keys.Properties.Settings.Default.foobar:
As you say, this obviously doesn't work. The specific reason is that the values for a case statement must be compile-time constants.
A simpler if comparison would probably be better. Since your value is a Keys and your property is a string, you'll need to convert one type to the other for comparison. I'll convert to a string for simplicity, or you could convert the string to the enum type.
if (myVar.ToString() == Properties.Settings.Default.foobar)
So instead of having, e.g.
switch (myVar) {
case Keys.F1:
// something
case Keys.F2:
// something
}
You would have:
if (myVar.ToString() == Properties.Settings.Default.foo) {
// something
} else if (myVar.ToString() == Properties.Settings.Default.bar) {
// something
}
Keys.F3 is a value of the Keys enumeration. So you'll need to convert your Properties.Settings.Default.foobar string into a value of the enumeration too.
Luckily, there is a built-in method to do that:
var foobarKey = (Keys)Enum.Parse(typeof(Keys), Properties.Settings.Default.foobar);
...
if (whatever == foobarKey)
{
...

Enum.Parse() or Switch

For converting a string to an enum, which of the following ways is better?
This code:
colorEnum color = (colorEnum)Enum.Parse(typeof(colorEnum), "Green");
or this:
string colorString = ...
colorEnum color;
switch (colorString)
{
case "Green":
color = colorEnum.Green;
break;
case "Red":
color = colorEnum.Red;
break;
case "Orange":
color = colorEnum.Orange;
break;
....
}
You should use the Enum.TryParse, if it fails you can handle the error correctly.
sample:
ColorsEnum colorValue;
if (Enum.TryParse(colorString, out colorValue))
if (Enum.IsDefined(typeof(Colors), colorValue) | colorValue.ToString().Contains(","))
Console.WriteLine("Converted '{0}' to {1}.", colorString, colorValue.ToString());
else
Console.WriteLine("{0} is not an underlying value of the Colors enumeration.", colorString);
else
Console.WriteLine("{0} is not a member of the Colors enumeration.", colorString);
(Warning: includes plug for my own open source library...)
Personally I'd use Unconstrained Melody, which ends up with cleaner and more typesafe code:
ColorEnum color = Enums.ParseName<ColorEnum>(text);
You can use TryParseName if you suspect it may be invalid. Obviously this requires an extra library, but hopefully you'll find other things in there helpful too :)
Enum.TryParse from .NET 4 is better than the other built-in options, but:
You won't catch non-enum types at compile time, e.g. Enum.TryParse<int>(...) will still compile; Unconstrained Melody really only allows enum types
Enum.TryParse will also parse "1" (or whatever the numeric value is when converted to a string) - if you really only expect names, I think it's better to only accept names
I definitely wouldn't switch on the string values - it means if you rename the enum values, you've got to remember to rename the case value as well.
And what about Enum.TryParse<TEnum> ?
string myColorStr = "red";
colorEnum myColor;
if(!Enum.TryParse<colorEnum>(myColorStr, true, out myColor))
{
throw new InvalidOperationException("Unknown color " + myColorStr);
}
Number 1 simply on readability and maintainability. If you extend the enum you need to do no extra work, wheras with 2 you have to add more cases to the switch statement
Because you added the tag 'performance', I'm going to go with the switch.
Yes, you will have to change the cases when you rename/add/remove anything in the enum. Well that's just too bad then. Any variant of Enum.Parse/TryParse uses a lot of weird code and some reflection, just take a look inside the function with ILSpy or such. Then there is also the issue of accepting "-12354" and even a comma-separated list of valid names (resulting in all of them ORed together) even when the enum doesn't have a [Flags] attribute.
As an alternative, you could make a dictionary that translates enum names to values. It should actually be faster than the switch, because a switch on strings also goes through a dictionary but you save the actual switch part.
Obviously both ways cost some more maintenance than enum.parse and variants; whether it's worth it is up to you, since out of all of us only you have enough knowledge of the project to make the performance/coding-time trade off.
1) Is much better. It's cleaner code. You are doing in one line what would take multiple in 2). Also, it's less bug prone. When you add another item to colorEnum, you would need to remember to extend 2) wheras 1) would just work.
You may also want some error handling on the Enum.Parse.
Other than the fact that the two different code snippets doesn't do the same thing, I'd use this:
colorEnum color;
if (!colorEnum.TryParse(colorString, true, out color)
color = colorEnum.Green; // Or whatever default value you wish to have.
If you don't have .NET 4.0 then I'd do something like this:
public static TEnum ToEnum<TEnum>(this string strEnumValue, TEnum defaultValue)
{
if (!Enum.IsDefined(typeof(TEnum), strEnumValue))
return defaultValue;
return (TEnum)Enum.Parse(typeof(TEnum), strEnumValue);
}
This is an Extension Method to string.
Personally, while I am totally fine with the Enum.Parse solution for non-performance scenarios (read: one off run of this function occasionally ... and there are many such scenarios to be sure), I can't countenance the thought of possibly involving some reflection type method when this function needs to be performed in a loop over hundreds/thousands plus enum values at once. Gack!
So the following is a solution that gets some of the best of both worlds.
Just retrieve all values of the enum at startup time or what not, whenever it works best for you (below is one way of doing that), and then construct a Dictionary with them.
private static Dictionary<string, Color> colorDictionary;
public static Dictionary<string, Color> ColorDictionary
{
get
{
if (colorDictionary== null) {
colorDictionary = new Dictionary<string, Color>();
var all = Enum.GetValues(typeof(Color)).OfType<Color>();
foreach (var val in all)
dict.Add(val.ToString(), val);
}
return colorDictionary;
}
}
I find the switch variant horrible since you will have to modify the switch everytime you change the enum also.
I like to use the TryParse that belongs to your enum. So you can use it like this
string colorString = .....
colorEnum color;
colorEnum.TryParse(colorString, out color);
Or if you don't care about the case of the string
colorEnum.TryParse(colorString, true, out color);
The returnvalue of TryParse is true if the string was a valid enum, false if not.
On a performance point of view, as enums are implemented as static fields, the parse method will probably ends up doing refection on then enum type and try a GetField method which might be faster than the case. On the other end, if 90% of the case, the color is green, the case will be very fast... Note that the CLR sometimes rearrange code internally, changing the order of the case based on statistic (actually, I'm not sure it does that but the doc claims it could).
I use the following, it gets you all the type safety while still not falling over when you add new values into the Enum, it's also very fast.
public static colorEnum? GetColorFromString(string colorString)
{
colorEnum? retVal = null;
if(Enum.IsDefined(typeof(colorEnum), colorString))
retVal = (colorEnum)Enum.Parse(typeof(colorEnum), colorString);
return retVal;
}
My test with 8 items in the enum shows this way to be faster than the switch method.
Or else you can use (the very slow way):
public static colorEnum? GetColorFromString(string colorString)
{
foreach (colorEnum col in Enum.GetValues(typeof(colorEnum)))
{
if (col.ToString().Equals(colorString))
{
return col;
}
}
return null;
}

Can I override ToString() for classes in a public API?

I'm writing a tool that interfaces with an API for another piece of software. Part of my tool will need to generate reports about the various objects found through the API, and I want these reports to contain simple strings that identify each object. By default I plan to use ToString() to generate the string for each object. However, not surprisingly I've found that the default ToString() implementations in this API aren't to descriptive.
Initially I was thinking of doing something like the code below with a long Switch statement. Although this would most likely become unmanageably long.
public string GetAPIObjectDescrition(object obj)
{
Type t = obj.GetType();
Switch(t)
{
Case typeof(SomeAPIType):
SomeAPIType x = (SomeAPIType)obj;
return x.SomeProperty;
Case typeof(SomeOtherAPIType):
SomeOtherAPITypex = (SomeOtherAPIType)obj;
return x.SomeOtherProperty;
default:
return x.ToString();
}
}
Next I tried using extension methods (see the code below). CustomObjectDescription() worked as expected, but when I tried to call ToString() it just returns the default ToString() results. I've never used extension methods before so I could be completely off base thinking something like this is even possible.
I can't guarantee that there will be a CustomObjectDescription() extension for every Type encountered in the API, so if I take this route I would end up having to use reflection each time to check if the current object has a GetObjectDescription() extension. I'd like to avoid using reflection if at all possible.
public static class APIObjectDescriptionExtensions
{
public static string ToString(this APIObject element)
{
return "ElementName = " + element.Name + " ElementID =" + element.Id.IntegerValue.ToString();
}
public static string CustomObjectDescription(this APIObject element)
{
return "ElementName = " + element.Name + " ElementID =" + element.Id.IntegerValue.ToString();
}
}
Does anyone have any other suggestions on how I should approach this problem? I'd prefer a solution where the code for each API Type is independent from one another (no giant Switch statement).
Also if possible I'd like the description string code for one type to inherit to sub types unless those types have their own unique description string code.
I think there might be a better solution that involves creating custom TypeConverters or maybe overriding/extending System.Convert.ToString()?
Update
I think the example below might help clarify what I'm trying to do. Ultimately I want to be able to take any arbitrary class from this API, the Type of which is not known until run time, and generate a description string. If the Type has my custom extension method then it should be used, otherwise the code should fall back on plain old ToString().
public static string GetDataDescription(object o)
{
//get the type of the input object
Type objectType = o.GetType();
//check to see if a description extension method is defined
System.Reflection.MethodInfo extensionMethod = objectType.GetMethod("MyDescriptionExtensionMethod");
if (extensionMethod != null)
{
//if a description extension method was found returt the result
return (string)extensionMethod.Invoke(o, new object[] { });
}
else
{
//otherwise just use ToString();
return o.ToString();
}
}
This code above doesn't work though because extension methods aren't found by GetMethod().
You could provide a wrapper for each of the classes similar to this:
public class SomeAPITypeWrapper : SomeAPIType
{
public override string ToString()
{
return SomeProperty;
}
}
public class SomeOtherAPITypeWrapper : SomeOtherAPIType
{
public override string ToString()
{
return SomeOtherProperty;
}
}
This certainly allows for using base classes/sub classes as requested in your question. It also keeps it clean and within your object model itself instead of in a switch statement or helper class.
Did you try using another name other then ToString() in your extension class? I am not completely sure about extension methods either, but I am guessing the base.ToString was getting called instead of yours. Possibly making a ToDescription() extension method would yield better results.
If a given method call can be resolved by an instance method and an extension method, the instance method is given preference. So extension methods need to be named such that they don't have same names as methods in the extended type.
From the code above, it seems that you don't control the source of APIObject and its derivations. So your options are 'Introduce Foreign Method' and 'Introduce Local Extension'
I'd try foreign method (which is similar to C# extension methods).. not sure why you would need reflection though. If the extension method doesn't exist, it'd be a compile-time error. How are you consuming this method ?
Finally switch statements are not that bad... unless they are very long/need frequent changes/duplicated across locations.
I suggest making a Dictionary<Type,Converter<object,string>>. Then you can look for a custom stringizer, and if none is found, call ToString.
Note, the dictionary will check for an exact match on types, so if you want to handle subclasses you'll have to write some additional code to see whether base types are listed in the dictionary (hint: if you match a base class, or even if you don't, go ahead and add the actual derived type to the dictionary so you won't have to recurse through the inheritance tree again).
Note that you can build an "open delegate" for Object.ToString() which conforms to the Converter<object,string> contract and use that as a default, even store it in the dictionary, instead of special-casing the call to ToString.
You could defer all tostringing to a separate concern of your application. StatePrinter (https://github.com/kbilsted/StatePrinter) is one such API where you can use the defaults or configure depending on types to print.
var car = new Car(new SteeringWheel(new FoamGrip("Plastic")));
car.Brand = "Toyota";
then print it
StatePrinter printer = new StatePrinter();
Console.WriteLine(printer.PrintObject(car));
and you get the following output
new Car() {
StereoAmplifiers = null
steeringWheel = new SteeringWheel()
{
Size = 3
Grip = new FoamGrip()
{
Material = ""Plastic""
}
Weight = 525
}
Brand = ""Toyota"" }
and with the IValueConverter abstraction you can define how types are printer, and with the FieldHarvester you can define which fields are to be included in the string.

Categories

Resources