c# polymorphism without method overloading (for a webmethod) - c#

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.

Related

Is it possible to return generic value while converting from string?

I have a system that relays on third party SW that stores data elements.
The data elements in the storage, have DataType and Value properties to describe the underline data object. Each DataElement can be fetched by name from the storage. (like an external database)
public class DataElemenet
{
public string Type { get; }
public string Value { get; }
}
I want to create a BL object to abstract the DataElement specifics in the following manner:
public class DataGetter
{
private readonly DataElement dataObject;
public DataGetter(string name)
{
this.dataObject = <third_party>.GetObject(name);
}
public int GetValue()
{
if (this.dataObject.Type != "integer")
throw new Exception();
return int.Parse(this.dataObject.Value);
}
}
Now, in the third party SW, Type can be a lot of different types (e.g., List<int>, double, List<string> ....)
As I can't overload the GetValue to return a different return value type, I tried a generic approach.
public T GetValue<T>()
{
if (typeof(T) != this.dataObject.Type)
throw new Exception();
return (T)Convert.ChangeType(this.dataObject.Value, typeof(T));
}
while this approach will work, I wish to optimize it in a following way (handle all data types by case):
EDIT
As was mentioned in one of the comments, this approach works only for primitives, and can't support the conversion to List<int> for example. So I tried to use the following approach:
public T GetValue<T>()
{
if (typeof(T) != this.dataObject.Type)
throw new Exception();
if (typeof(T) == typeof(int))
return int.Parse(this.dataObject.Value);
else if (typeof(T) == typeof(bool))
return bool.Parse(this.dataObject.Value);
....
}
The compiler if complaining as it can't convert a int / bool (in the above cases) to T.
Can this be done?
You can rely on the new IParsable<T> interface from .NET7 which has a generic static Parse method which you can use in generic contexts.
Keeping your original attempt in place, this could look something like:
public T GetValue<T>()
where T : IParsable<T>
{
if (typeof(T) != this.dataObject.Type)
throw new Exception();
return T.Parse(this.dataObject.Value, CultureInfo.InvariantCulture);
}
Notice that the type you pass now must implement the static abstract Parse method from IParsable, which the vast majority of standard primitive and basic types do. If you then want to support things such as arbitrary lists from a string, you can create your own custom collections that implement IParsable and put the conversion from string to list there.
The advantage of this approach is that it is truly polymorphic: it doesn't force you to check for all possible types in a gigantic switch statement. Thus it is vastly more maintainable and extensible.
Yes this is possible: you need to cast to object first (be aware of boxing/unboxing in that cases).
public T GetValue<T>()
{
if (typeof(T) != this.dataObject.Type)
throw new Exception();
if (typeof(T) == typeof(int))
return (T)(object)int.Parse(this.dataObject.Value);
else if (typeof(T) == typeof(bool))
return (T)(object)bool.Parse(this.dataObject.Value);
....
}
DEMO

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

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);

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.

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.

Categories

Resources