Making a (more) general converter for simple values [duplicate] - c#

This question already has answers here:
Converting from String to <T>
(5 answers)
Closed 2 years ago.
I've used the following two extension methods for converting the incoming strings into what I need them to be. They are used on data that has been converted to strings, but where the original type is always known.
public static int ToInt(this string self)
{
try { return Convert.ToInt32(self); }
catch { return default(int); }
}
public static double ToInt(this string self)
{
try { return Convert.ToDouble(self); }
catch { return default(double); }
}
I just learned that the information flow is going to be extended and contain other types, as well. Adding a new extension method for each is a sure way to insanity in the long run, not to mention code redundancy. So I attempted to make it more general.
public static T ToType<T>(this string self)
{
if (typeof(T) == typeof(int))
try { return Convert.ToInt32(self); }
catch { return default(int); }
}
However, the compiler has issues with that (regarding type, of course). I've tried casting in the first return, and using the provided type in the second, but the issue still remains.
public static T ToType<T>(this string self)
{
if (typeof(T) == typeof(int))
try { return (T)Convert.ToInt32(self); }
catch { return default(T); }
}
Can it be done at all, or am I going to end up creating many similar extension methods? Please keep in mind that since I will always know what types are being served, I only need to cover those, in case a fully generic and type safe approach isn't possible, or is very cumbersome.
Also, please note that I had surgery yesterday, and I'm still a bit off, so the answer might be embarrassingly simple.

Along the lines of another question's answer, you can accomplish this using Convert.ChangeType() method.
public static T Get<T>(this String self)
{
return (T)Convert.ChangeType(self, typeof(T));
}
Or even more sophisticated version with a fallback in case the conversion fails.
public static T Get<T>(this String self, T fallBack = default(T))
{
try { return (T)Convert.ChangeType(self, typeof(T)); }
catch { return fallBack; }
}
The usage is then as follows.
String source = ...
Guid guid = source.Get<Guid>();
int number = source.Get<int>(42);

Related

Variable generic return type in C#

Is there any way to have a method return any one of a number of generic types from a method? For example, I have the following:
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
if(typeof(T) == typeof(Int32))
{
return Int32.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(Double))
{
return Double.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(String))
{
return element.Attribute(attribute).Value;
}
if(typeof(T) == typeof(ItemLookupType))
{
return Enum.Parse(typeof(T), element.Attribute(attribute).Value);
}
}
(This is only a very quick mockup, I'm aware that any production code would need to be significantly more thorough in null checks etc...)
But the compiler doesn't like it, complaining that Int32 cannot be implicitly converted to T (it doesn't work with a cast either). I can understand that. At compile time it has no way to know what T is, but I'm checking it beforehand. Is there anyway I can make this work?
I've done these types of generic methods in the past. The easiest way to get type inference is to provide a generic converter function.
public static T ParseAttributeValue<T>
(this XElement element, string attribute, Func<string, T> converter)
{
string value = element.Attribute(attribute).Value;
if (String.IsNullOrWhiteSpace(value)) {
return default(T);
}
return converter(value);
}
You can use it like the following:
int index = element.ParseAttributeValue("index", Convert.ToInt32);
double price = element.ParseAttributeValue("price", Convert.ToDouble);
You can even provide your own functions and have all the fun in the world (even return anonymous types):
ItemLookupType lookupType = element.ParseAttributeValue("lookupType",
value => Enum.Parse(typeof(ItemLookupType), value));
var item = element.ParseAttributeValue("items",
value => {
List<string> items = new List<string>();
items.AddRange(value.Split(new [] { ',' }));
return items;
});
.Net already has a bunch of great string conversion routines you can use! A TypeConverter can do most of the heavy lifting for you. Then you don't have to worry providing your own parsing implementations for built-in types.
Note that there are locale-aware versions of the APIs on TypeConverter that could be used if you need to handle parsing values expressed in different cultures.
The following code will parse values using the default culture:
using System.ComponentModel;
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter.CanConvertFrom(typeof(string)))
{
string value = element.Attribute(attribute).Value;
return (T)converter.ConvertFromString(value);
}
return default(T);
}
This will work for a lot of built-in types, and you can decorate custom types with a TypeConverterAttribute to allow them to participate in the type conversion game too. This means that in the future you will be able to parse new types without having to change the implementation of the ParseAttributeValue.
see: http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter.aspx
Why are you using the type parameter as the return type at all? This would work, just requires a cast after calling:
public static Object ParseAttributeValue<T>(this XElement element, string attribute)
{
if(typeof(T) == typeof(Int32))
{
return Int32.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(Double))
{
return Double.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(String))
{
return element.Attribute(attribute).Value;
}
if(typeof(T) == typeof(ItemLookupType))
{
return Enum.Parse(typeof(T), element.Attribute(attribute).Value);
}
}
Or better yet:
public static Int32 ParseAsInt32(this XElement element, string attribute)
{
return Int32.Parse(element.Attribute(attribute).Value);
}
// etc, repeat for each type
This second approach has the additional benefit of having a much higher likelihood of getting inlined, plus it will (for value types like Int32) prevent the need to box/unbox the value. Both of these will cause the method to perform somewhat faster.
Not sure if this is exactly what you want, but you can make the returns work if you cast to object first then to T
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
if (typeof(T) == typeof(Int32))
{
return (T)(object)Int32.Parse(element.Attribute(attribute).Value);
}
if (typeof(T) == typeof(Double))
{
return (T)(object)Double.Parse(element.Attribute(attribute).Value);
}
if (typeof(T) == typeof(String))
{
return (T)(object)element.Attribute(attribute).Value;
}
return default(T);
}
However you still have to provide T at compile time, calling the method like:
int value = element.ParseAttributeValue<int>("attribute");
Here's two ways of doing it...
static T ReadSetting<T>(string value)
{
object valueObj = null;
if (typeof(T) == typeof(Int32))
valueObj = Int32.Parse(value);
return (T)valueObj;
}
static dynamic ReadSetting2<T>(string value)
{
if (typeof(T) == typeof(Int32))
return Int32.Parse(value);
throw new UnsupportedException("Type is unsupported");
}
static void Main(string[] args)
{
int val1 = ReadSetting<Int32>("2");
int val2 = ReadSetting2<Int32>("3");
}
With C++ templates, this kind of thing would work, but only if each piece of code were in a different, separate specialization. The thing that makes that work is that unused function templates are not compiled (or more accurately: not fully instantiated), so the fact that a piece of code would be invalid if that copy of the template were instantiated with a different type doesn't come up.
C# is different, and AFAIK there's no specialization for generics. One way to accomplish what you are trying to do, while working within the limitations of C# would be to create one function with a more abstract return type, and use the ParseAttributeValue only to cast it to T.
So you would have:
private static Object AbstractParseValue(System.Type t, XElement element, string attribute)
and
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
return (T)AbstractParseValue(typeof(T), element, attribute);
}
I would suggest that rather than testing the type parameter every time the routine is executed, you should create a generic static class something like this:
internal static class ElementParser<T>
{
public static Func<XElement, string, T> Convert = InitConvert;
T DefaultConvert(XElement element, string attribute)
{
return Default(T); // Or maybe throw exception, or whatever
}
T InitConvert(XElement element, string attribute)
{
if (ElementParser<int>.Convert == ElementParser<int>.InitConvert)
{ // First time here for any type at all
Convert = DefaultConvert; // May overwrite this assignment below
ElementParser<int>.Convert =
(XElement element, string attribute) =>
Int32.Parse(element.Attribute(attribute).Value);
ElementParser<double>.Convert =
(XElement element, string attribute) =>
Int32.Parse(element.Attribute(attribute).Value);
// etc. for other types
}
else // We've done other types, but not this type, and we don't do anything nice for it
{
Convert = DefaultConvert;
}
return Convert(element, attribute);
}
}
public static T ParseAttributeValue(this XElement element, string attribute)
{
ElementParser<T>.Convert(element, attribute);
}
Using this approach, one will only have to do special handling the first time a particular type is used. After that, the conversion can be performed using only a single generic delegate invocation. Once could easily add any number of types, and even allow converters to be registered for any desired type at runtime.

How do I write a generic Convert function?

I am trying to write a generic convert function but I don't know how do I do that. This is my skeleton:
public static T ConvertByGenerics<T>(string value)
{
//what do I write here?
return default(T);
}
Can anybody help me out? What do I write within the function to dynamically convert string into type T?
Try something like:
public T ConvertByGenerics<T>(string value, T defaultValue)
{
if (!string.IsNullOrEmpty(value))
{
return (T)Convert.ChangeType(value, typeof(T));
}
return defaultValue;
}
There are some more things you might try, but they involve dynamic methods.
There is not enough exception handling in the snippet, and can certainly be optimized somewhat.
public static T ConvertByGenerics<T>(string input) {
// be mindful of boxing
if (input is T) {
return (T)(object)input;
}
if (input == null) {
// throw arugment exception
}
// can check for int, long ......
if (typeof(T).IsEnum) {
return (T)System.Enum.Parse(typeof(T), input, true);
}
if (typeof(T).IsAssignableFrom(typeof(string))) {
return (T)(object)input;
}
try {
return (T)Convert.ChangeType(input, typeof(T));
}
catch { //do nothing
}
// might want to cache some converters
System.ComponentModel.TypeConverter converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
if (converter.CanConvertFrom(typeof(string))) {
return (T)converter.ConvertFrom(input);
}
else {
// better though to throw an exception here
return default(T);
}
}
What you want is not possible.
In order to support any conceivable type, you need to know how it will be represented as a string - some of the built in value types have Parse methods that "understand" certain formats of strings and can parse them into the type, but there is absolutely no way to generically do this for every conceivable type.
You need to write code to convert from a string to every type - this is not feasible for every type in existence.

c# polymorphism without method overloading (for a webmethod)

Okay, so I realised after writing some overloaded methods that webmethods can't be overloaded (by realised I mean VS threw a paddy and wouldn't allow me to update the service references). I have tried to get around that like this:
public string DoPing<T>(T IP)
{
if (typeof(T) == typeof(string))
{
return DoPingString(IP);
}
if (typeof(T) == typeof(IPAddress))
{
return DoPingIP(IP);
}
throw new Exception("Programmer Error");
}
But I'm getting a cannot convert from T to string/Ipadress error when I call the respective (renamed) methods.
Can someone explain why it doesn't work, and possibly either fix it or give me an alternate solution?
Thanks in advance.
Edit: Good point, generics are probably overkill (I tried for another solution and failed before trying this).
DoPingString(string String) and DoPingIP(IPAdress Address) are the signatures.
I will give the tick to the closest answer tomorrow. I solved the problem in a separate way.
You can use WebMethodAttribute :
[WebMethod(MessageName = "DoPingIPAddress")]
public string DoPing(IPAddress ip) { }
[WebMethod(MessageName = "DoPingString")]
public string DoPing(string ip) { }
But from the client side, you'll have two different methods : it's web services/SOAP constraints.
Documentation
You're not using generics the way it was intended. The compiler has no idea what type T is, so it won't just let you implicitly or explicitly cast to String or IPAddress.
Here's a version that works:
public string DoPing<T>(T IP)
{
if (typeof(T) == typeof(string))
{
return DoPingString((String)Convert.ChangeType(IP, typeof(String)));
}
if (typeof(T) == typeof(IPAddress))
{
return DoPingIP((IPAddress)Convert.ChangeType(IP, typeof(IPAddress)));
}
throw new Exception("Programmer Error");
}
However, since you're using generics with no constraint, you gain no benefit from the generic implementation. Why not just take an object?
public string DoPing(Object IP)
{
if (IP.GetType() == typeof(string))
{
return DoPingString((String)IP);
}
if (IP.GetType() == typeof(IPAddress))
{
return DoPingIP((IPAddress)IP);
}
throw new Exception("Programmer Error");
}
Of course, the simpler and easier approach would be to simply overload your function, i.e.:
public string DoPing(string IP)
{
return DoPingString(IP);
}
public string DoPing(IPAddress IP)
{
return DoPingIP(IP);
}
Try using Convert.ChangeType method then cast as usual:
if (typeof(T) == typeof(string))
{
return DoPingString((string)Convert.ChangeType(IP, typeof(string)));
}
if (typeof(T) == typeof(IPAddress))
{
return DoPingIP((IPAddress)Convert.ChangeType(IP, typeof(IPAddress)));
}
It sounds like you want the KnownTypeAttribute available in WCF. But seeing as you can't use that here and you definitely want only one method then I think the only way is to just offer two parameters. Just add some validation to check for nulls and pass them on to your private helper methods.
[WebMethod]
public string DoPing(string ipString, IPAddress ipAdress)
{
if(ipString != null)
{
DoPing(ipString);
}
if(ipAdress != null)
{
DoPing(ipAdress);
}
}
I would better do this:
public string DoPing(IPAddress ip)
{
...logic...
}
public string DoPing(String ip)
{
...logic...
}
Try to avoid unnecessary patterns and templates.

Generic TryParse Extension method

Code taken from here
I would like to hear some expert opinions on this extension method. I do plan to use it, but would like to hear about any known problems i may face.
Am i better of using on primative types TryParse methods?
public static T? TryParse<T>(this object obj) where T : struct
{
if (obj == null) return null;
T? result = null;
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
{
try
{
string str = obj.ToString();
result = (T)converter.ConvertFromString(str);
}
catch (Exception ex)
{
throw ex;
}
}
return result;
}
The TryParse pattern is best following the standard pattern, which allows use with non-structs, too:
public static bool TryParse<T>(string s, out T value) {
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
try {
value = (T) converter.ConvertFromString(s);
return true;
} catch {
value = default(T);
return false;
}
}
Note I've accepted a string here, because that is what me most commonly mean by TryParse; otherwise, Convert.ChangeType might be more appropriate.
I see no reason for this to be an extension method (as per this in the question's example), and certainly it is inadvisable to pollute object with too many extension methods.
The extensions below might be useful to you. They work on any type that has a Parse or TryParse method...
They come from my Extensions library here:
http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx
Although that project is probably a bit out-of-date...I'll have to update it as some point :-D
Hope this helps!
public static class StringExtensions
{
public static TOut ParseOrDefault<TOut>(this string input)
{
return input.ParseOrDefault(default(TOut));
}
public static TOut ParseOrDefault<TOut>(this string input, TOut defaultValue)
{
Type type = typeof(TOut);
MethodInfo parseMethod = type.GetMethod("Parse", new Type[] { typeof(string) });
if (parseMethod != null)
{
var value = parseMethod.Invoke(null, new string[] { input });
return (value is TOut ? (TOut)value : defaultValue);
}
else { return defaultValue; }
}
public static bool TryParseOrDefault<TOut>(this string input, out TOut output)
{
return input.TryParseOrDefault(out output, default(TOut));
}
public static bool TryParseOrDefault<TOut>(this string input, out TOut output, TOut defaultValue)
{
output = defaultValue;
Type type = typeof(TOut);
MethodInfo parseMethod = type.GetMethod(
"TryParse",
new Type[] { typeof(string), typeof(TOut).MakeByRefType() });
if (parseMethod != null)
{
object[] parameters = new object[] { input, output };
var value = parseMethod.Invoke(null, parameters);
if (value is bool)
{
bool successful = (bool)value;
if (successful)
{
output = (TOut)parameters[1];
return true;
}
}
}
return false;
}
}
Generics are most useful when you want to vary the public contract of a method or class, and the internals of the method or class don't really care (or care much) about the type that varies.
Some examples:
List<T> is a collection you can put things in, and internally the class doesn't care (much) about what that type is.
T System.Linq.Enumerable.First<T>(IEnumerable<T> source) returns the first element out of a bunch of elements. This method doesn't need to know internally what type that is in order to get the job done.
By contrast, a parsing method must change its behavior based on the type of the result. In the supplied method, there is Strategy which pushes the behaviors out to other methods, but there is a runtime cost for that choice.
The alternative is to let the caller (who must know the Type or they couldn't call the generic method with it), pick the converter. This choice is able to be made at design time or compile time and so incurs 0 runtime cost.
Side Note: Please don't use the re-throw everything idiom. All it does is reset the call stack and you don't ever want to do that.
catch (Exception ex)
{
throw ex;
}
For simpler code, you can do this:
T value = (T)Convert.ChangeType(value, typeof(T));
Credit to Thomas Levesque at https://stackoverflow.com/a/1465930/24315.
It uses reflection and thus may be slow, if performance is an issue.

C# Generics and Casting Issue

I am having trouble casting an object to a generic IList. I have a group of in statements to try to work around this, but there has to be a better way to do this.
This is my current method:
string values;
if (colFilter.Value is IList<int>)
{
values = BuildClause((IList<int>)colFilter.Value, prefix);
}
else if (colFilter.Value is IList<string>)
{
values = BuildClause((IList<string>)colFilter.Value, prefix);
}
else if (colFilter.Value is IList<DateTime>)
{
values = BuildClause((IList<DateTime>)colFilter.Value, prefix);
}
else if (...) //etc.
What I want to do is this:
values = BuildClause((IList<colFilter.ColumnType>)colFilter.Value, prefix);
or
values = BuildClause((IList<typeof(colFilter.ColumnType)>)colFilter.Value, prefix);
or
values = BuildClause((IList<colFilter.ColumnType.GetType()>)colFilter.Value, prefix);
Each of these produces this compiler error:
The type or namespace name 'colFilter' could not be found (are you missing a using directive or an assembly reference?)
In my example, colFilter.ColumnType is int, string, datetime, etc. I am not sure why this does not work.
Any ideas?
EDIT: This is C#2.0
EDIT #2
Here is the BuildClause method (I have overloads for each type):
private static string BuildClause(IList<int> inClause, string strPrefix)
{
return BuildClause(inClause, strPrefix, false);
}
private static string BuildClause(IList<String> inClause, string strPrefix)
{
return BuildClause(inClause, strPrefix, true);
}
private static string BuildClause(IList<DateTime> inClause, string strPrefix)
{
return BuildClause(inClause, strPrefix, true);
}
//.. etc for all types
private static string BuildClause<T>(IList<T> inClause, string strPrefix, bool addSingleQuotes)
{
StringBuilder sb = new StringBuilder();
//Check to make sure inclause has objects
if (inClause.Count > 0)
{
sb.Append(strPrefix);
sb.Append(" IN(");
for (int i = 0; i < inClause.Count; i++)
{
if (addSingleQuotes)
{
sb.AppendFormat("'{0}'", inClause[i].ToString().Replace("'", "''"));
}
else
{
sb.Append(inClause[i].ToString());
}
if (i != inClause.Count - 1)
{
sb.Append(",");
}
}
sb.Append(") ");
}
else
{
throw new Exception("Item count for In() Clause must be greater than 0.");
}
return sb.ToString();
}
There's no way to relate method overloading and generics: although they look similar, they are very different. Specifically, overloading lets you do different things based on the type of arguments used; while generics allows you to do the exact same thing regardless of the type used.
If your BuildClause method is overloaded and every overload is doing something different (not just different by the type used, but really different logic, in this case - choosing whether or not to add quotes) then somewhere, ultimately, you're gonna have to say something like "if type is this do this, if type is that do that" (I call that "switch-on-type").
Another approach is to avoid that "switch-on-type" logic and replace it with polymorphism. Suppose you had a StringColFilter : ColFilter<string> and a IntColFilter : ColFilter<int>, then each of them could override a virtual method from ColFilter<T> and provide its own BuildClause implementation (or just some piece of data that would help BuildClause process it). But then you'd need to explicitly create the correct subtype of ColFilter, which just moves the "switch-on-type" logic to another place in your application. If you're lucky, it'll move that logic to a place in your application where you have the knowledge of which type you're dealing with, and then you could explicitly create different ColFilters at different places in your application and process them generically later on.
Consider something like this:
abstract class ColFilter<T>
{
abstract bool AddSingleQuotes { get; }
List<T> Values { get; }
}
class IntColFilter<T>
{
override bool AddSingleQuotes { get { return false; } }
}
class StringColFilter<T>
{
override bool AddSingleQuotes { get { return true; } }
}
class SomeOtherClass
{
public static string BuildClause<T>(string prefix, ColFilter<T> filter)
{
return BuildClause(prefix, filter.Values, filter.AddSingleQuotes);
}
public static string BuildClause<T>(string prefix, IList<T> values, bool addSingleQuotes)
{
// use your existing implementation, since here we don't care about types anymore --
// all we do is call ToString() on them.
// in fact, we don't need this method to be generic at all!
}
}
Of course this also gets you to the problem of whether ColFilter should know about quotes or not, but that's a design issue and deserves another question :)
I also stand by the other posters in saying that if you're trying to build something that creates SQL statements by joining strings together, you should probably stop doing it and move over to parameterized queries which are easier and, more importantly, safer.
What does the function BuildClause() look like.
It seems to me that you can create BuildClause() as an extension method on IList, and you can append the values together. I assume that you just want to call .ToString() method on different types.
If you use generics properly in C# 3.0, you can achieve what you need through implicit typing (int C# 2.0 you might need to specify the type). If your BuildClause method is made generic, it should automatically take on whatever type is passed in to its generic parameter(s):
public IList<T> BuildClause<T>(IList<T> value, object prefix)
{
Type type = typeof(T);
if (type == typeof(string))
{
// handle string
}
else if (type == typeof(int))
{
// handle int
}
// ...
}
public class ColumnFilter<T>:
where T: struct
{
public IList<T> Value { get; set; }
}
var colFilter = new ColumnFilter<string>
{
Value = new { "string 1", "string 2", "string 3" }
}
IList<string> values = BuildClause(colFilter.Value, prefix);
With generics, you can drop the ColumnType property of your ColumnFilter. Since it is generic, along with your BuildClause method, you are easily able to determine the type by doing typeof(T).
I am having trouble casting an object to a generic
Casting is a run-time operation.
Generic is compile-time information.
Don't cross the streams.
Also - if you used a decent sql parameterization generator - it will add the single quotes for you.
I don't understand the question. It works for me. It could be as simple as droping the cast? What am I missing?
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApplication1 {
class Foo<T> : List<T> {
}
class Program {
static void Main(string[] args) {
var a = new Foo<int>();
a.Add(1);
var b = new Foo<string>();
b.Add("foo");
Console.WriteLine(BuildClause(a, "foo", true));
Console.WriteLine(BuildClause(b, "foo", true));
}
private static string BuildClause<T>(IList<T> inClause, string strPrefix, bool addSingleQuotes) {
StringBuilder sb = new StringBuilder();
//Check to make sure inclause has objects
if (inClause.Count == 0)
throw new Exception("Item count for In() Clause must be greater than 0.");
sb.Append(strPrefix).Append(" IN(");
foreach (var Clause in inClause) {
if (addSingleQuotes)
sb.AppendFormat("'{0}'", Clause.ToString().Replace("'", "''"));
else
sb.Append(Clause.ToString());
sb.Append(',');
}
sb.Length--;
sb.Append(") ");
return sb.ToString();
}
}
}
The type for the IList must be known at compile time. Depending on what you want to do, you might be able to cast the list to an IList or IEnumerable (without generics) and then iterate over the objects

Categories

Resources