I'm just learning about generics and have a question regarding method return values.
Say, I want a generic method in the sense that the required generic part of the method signature is only the return value. The method will always take one string as it's parameter but could return either a double or an int. Is this possible?
Effectively I want to take a string, parse the number contained within (which could be a double or an int) and then return that value.
Thanks.
Something like this?
void Main()
{
int iIntVal = ConvertTo<int>("10");
double dDoubleVal = ConvertTo<double>("10.42");
}
public T ConvertTo<T>(string val) where T: struct
{
return (T) System.Convert.ChangeType(val, Type.GetTypeCode(typeof(T)));
}
You cannot return either a double or an int from a generic method without it also returning any other type.
I might, for example, have a Foo class and your generic parse method, without any constraint, will allow this call to be made:
Foo result = Parse<Foo>("111");
The best that you can do with numbers is constrain on your function by only allowing struct (value-types) to be used.
T Parse<T>(string value) where T : struct;
But this will allow all number types, plus any other value-type.
You can constrain by interface type, but there isn't an INumeric interface on double or int so you're kind of stuck.
The only thing that you can do is throw an exception if the wrong type is passed in - which generally isn't very satisfying.
Your best approach, in this case, is to abandon generics and use separately named methods.
double ParseDouble(string value);
int ParseInteger(string value);
But, of course, this won't help you learn generics. Sorry.
Yes it's possible.
Example:
public T ParseValue<T>(String value) {
// ...
}
You could do something like ...
public TResult Parse<TResult>(string parameter)
{
/* do stuff */
}
And use it like ...
int result = Parse<int>("111");
And then it will depend on your implementation in the Parse method.
Hope it helps.
Related
I wrote a Generic Class:
public class Interval<T> where T : IComparable // for checking that Start < End
{
public T Start { get; set; }
public T End { get; set; }
...
}
And I use this class with DateTime, int, etc.
I need a Duration property that returns a duration like:
public object Duration
{
get
{
return End - Start;
}
}
But when this property is included in my class, the compiler raises a logical error on the - operator.
What can I do to achieve this goal normally, or should I ignore it?
Try something like this:
static void Main(string[] args)
{
Tuple<int, bool> value = JustAMethod<int>(5, 3);
if (value.Item2)
{
Console.WriteLine(value.Item1);
}
else
{
Console.WriteLine("Can't substract.");
}
}
public static Tuple<T, bool> JustAMethod<T>(T arg1, T arg2)
{
dynamic dArg1 = (dynamic)arg1;
dynamic dArg2 = (dynamic)arg2;
dynamic ret;
try
{
ret = dArg1 - dArg2;
return new Tuple<T, bool>(ret, true);
}
catch
{
return new Tuple<T, bool>(default(T), false);
}
}
How this works: first, you convert the arguments to a dynamic type, and you can easily use operators on the dynamic type. If you wouldn't be able to use the operators, then an exception would be thrown at runtime. So, if you try to substract two objects that you actually can't substract, we'll catch the exception and return false as the second item in the Tuple.
This is not possible with generics in C# - at least not directly. It has been a highly requested feature on Connect for a long time.
You will need to make your types implement some interface that has a member that can be used, and constrain the class to that, or use one of the workarounds listed in the Connect bug (none of which are perfect), or a separate approach like MiscUtil's generic operators.
this work
public object Duration
{
get
{
return (dynamic)End - (dynamic)Start;
}
}
but no check, and slow
Check Jon Skeet's Misc Util https://jonskeet.uk/csharp/miscutil/
And here the generic operators by Marc Gravell: https://jonskeet.uk/csharp/miscutil/usage/genericoperators.html
The compiler does this so you don't write buggy code, its the whole point of generics and the concept of type safe programming.
If you need a method that subtracts dates write one that accepts a date, and if you need another one for integers, guess what you should write one for integers. Generics are not there so that the compiler can assume responsibility for any type. Think about it what if I wanted the difference between two objects, how would I do that with your generic method?
Or as #Reed Copsey mentioned you can constrain a class to it.
While this may seem like a major restriction, you need to remember that generics are generic. Of course, the System.Int32 type can work just fine with the binary operators of C#. However, for the sake of argument, if <T> were a custom class or structure type, the compiler cannot assume it has overloaded the +, -, *, and / operators.
I have the following C# class:
public class MyType<T>
{
public void TryParse(string p_value)
{
T value ;
Parser.TryParse(p_value, out value);
// Do something with value
}
}
The point is to call the right Parser.TryParse method, depending on the generic type T.
This uses the following static class:
static public class Parser
{
static public void TryParse(string p_intput, out object p_output)
{
// Do something and return the right value
}
static public void TryParse(string p_intput, out double p_output)
{
// Do something and return the right value
}
static public void TryParse(string p_intput, out int p_output)
{
// Do something and return the right value
}
}
I expected this to work: In the worst case, the "object" TryParse would be called. Instead, I have two compilation errors:
CS1502: The best overloaded method match for 'Parser.TryParse(string, out object)' has some invalid arguments
CS1503: Argument 2: cannot convert from 'out T' to 'out object'
Question 1: I don't understand why this doesn't work: I can be naive, but aren't all C# objects supposed to derive from "object" ? Why T cannot be converted to object?
Question 2: How can I dispatch a method with generic type T into the right non-generic methods (i.e. MyType<T>.TryParse calling the right Parser.TryParse according to the right type of T) ?
Note
The question was edited to reflect the original question intent (as written in the title: How to dispatch C# generic method call into specialized method calls)
Actually, ref and out parameters do not allow type variation. So, to pass a variable to a method expecting an out object parameter, that variable must be declared as object.
From the specification (§10.6.1.2 and §10.6.1.3)
When a formal parameter is a reference parameter, the corresponding argument in a method invocation must consist of the keyword ref followed by a variable-reference (§5.3.3) of the same type as the formal parameter.
When a formal parameter is an output parameter, the corresponding argument in a method invocation must consist of the keyword out followed by a variable-reference (§5.3.3) of the same type as the formal parameter.
See: Why do ref and out parameters not allow type variation? for some insight into why.
Bonus question: How can I dispatch a method with generic type T into the right non-generic methods (i.e. MyType<T>.TryParse calling the right Parser.TryParse according to the right type of T)?
I'm going to turn it back around on you. Why are you doing this? If you are invoking MyType<T>.TryParse as, say, MyType<int>.TryParse, why not call Int32.TryParse directly? What is this extra layer buying you?
I know this is somewhat low-tech, but I have had the same problem, where I solved it by making a Dictionary<Type, Parser> containing the individual parsers. I will be interested in what answers this questions bring.
Regards,
Morten
Current solution
The current solution I use at work is based on dynamic dispatch, that is, the keyword dynamic as defined on C# 4.0.
The code is something like (from memory) :
public class Parser
{
static public void TryParse<T>(string p_input, out T p_output)
{
// Because m_p is dynamic, the function to be called will
// be resolved at runtime, after T is known...
m_p.DoTryParse(p_input, out p_output) ;
}
// The dynamic keyword means every function called through
// m_p will be resolved at runtime, at the moment of the call
private dynamic m_p = new Parser() ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
private void DoTryParse(string p_input, out double p_output)
{ /* Do something and return the right value */ }
private void DoTryParse(string p_input, out int p_output)
{ /* Do something and return the right value */ }
// etc.
private void DoTryParse<T>(string p_input, out T p_output)
{
// fallback method... There are no dedicated method for T,
// so p_output becomes the default value for T
p_output = default(T) ;
}
}
The elegant part is that it can't fail (the fallback function will be called, if none with a better signature match is found), and that it follows a simple pattern (overload the function).
Of course, the real-life, production code is somewhat different, and more complicated because, with but one public static method, I want to :
parse both reference objects (classes) and value objects (structs)
parse enums
parse nullable types
I want to offer the user the possibility to derive from Parser to offer its own overloads in addition to the default ones
But I guess the use of dynamic in the current solution is, in the end, the same thing as doing reflection as done in the original answer below. Only the "notation" changes.
Conclusion, I now have the following method :
public class Parser
{
static public void TryParse<T>(string p_input, out T p_output)
{
// etc.
}
}
which is able to parse anything, including in situations where T is not known at compile time (because the code is generic).
Original answer
Jason's answer was right about the first question (about the compiler errors). Still, I had no solution to my problem (dispatching from a generic method to non-generic methods according to the runtime generic type T).
I tried LukeH's answer, but it didn't work: The generic method is always called, no matter what (even when removing the out qualifier of the second parameter).
Morten's answer is the most sane one that should works, but it doesn't make use of reflection.
So, to solve my own problem, I used reflection. This needs the rewriting of the generic TryParse method:
public class MyType<T>
{
public void TryParse(string p_value)
{
T value = default(T);
// search for the method using reflection
System.Reflection.MethodInfo methodInfo = typeof(Parser).GetMethod
(
"TryParse",
new System.Type[] { typeof(string), typeof(T).MakeByRefType() }
);
if (methodInfo != null)
{
// the method does exist, so we can now call it
var parameters = new object[] { p_value, value };
methodInfo.Invoke(null, parameters);
value = (T)parameters[1];
}
else
{
// The method does not exist. Handle that case
}
}
}
I have the source code available if needed.
This problem intrigued me, so I did some research and found a nice thing by Paul Madox. This seems to do the trick.
public static T SafeParseAndAssign<T>(string val) where T: new()
{
try
{
T ValOut = new T();
MethodInfo MI = ValOut.GetType().
GetMethod("Parse", new Type[] { val.GetType() });
return (T)MI.Invoke(ValOut, new object[] { val });
}
catch
{
// swallow exception
}
return default(T);
}
Hey, I think I have the wrong idea here, but I'm not sure what is best. I want a class with a member variable that can be of any type, depending on what is needed at the time. So far, I have something like this:
public class ConfigSetting<T> {
private T value;
public T GetValue() {
return value;
}
public void ChangeValue() {
}
public ConfigSetting(string heading, string key) {
this.value = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
}
}
The type returned by the right side of the 'this.value' line is a string, currently. I know here it seems like I have no need to use anything other than the string type, but eventually I will expand the constructor, such that 'this.value' could be a string, int, float, or bool.
Anyway, my compiler says "Cannot convert 'string' to 'T'", so I assume I'm doing something very backwards.
Thank you.
You're running into problems because this is not a good use of generics. If the generic type parameter can only be constructed in four different ways -- string, float, bool and int -- then this isn't very generic. I expect that a generic thing can be any type at all.
If I had a thing that could only be one of four types then I would model it like this:
abstract class ConfigSetting
{ /* shared code here */ }
class TextSetting : ConfigSetting
{ /* Code here to handle string settings */ }
class BooleanSetting : ConfigSetting
{ /* ...
and so on. I would probably then give each of them an internal constructor, and make the base class into a factory for the derived classes, using the factory pattern.
Only use generics if your solution is truly generic. Like List<T>, for example, can be a list of anything: ints, strings, arrays, dictionaries, functions, whatever. If the thing you are modeling has a small number of possible types, just make one for each type.
Well, what conversion did you expect it to apply? If you expect the value to already be of the right type, you could do:
object tmp = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
this.value = (T) tmp;
Note that you have to go through object either implicitly (as here) or with an explicit cast:
this.value = (T)(object) DerivedMethods.configsettings... (etc);
The set of conversions provided for generic types is somewhat limited. But it should work if the original value is genuinely correct.
You need to cast the returned String to T:
public ConfigSetting(string heading, string key) {
this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
}
I think you shouldn't necessarily use generics to plan ahead for all possible future scenarios because you will likely run into edge cases in the future and have to modify the code regardless.
However if you already have multiple scenarios that a generic would fit to, then you can benefit from the logic reuse now and can test them all properly.
I see others have already provided code answers so I'll stop here.
I assume that
DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue
is a string.
You can't assign a string to this.value because the type of this.value is T and could be anything, such as types to which strings are not assignable.
One solution is to remove the generic parameter and make value a string, and then provide different ways of accessing it which parse bools, floats, or whatever as required.
public float GetFloatValue {
get { return float.Parse(this.value); }
}
// etc
It looks like you're trying to assign a string (configsettings.SettingGroups[heading].Settings[key].RawValue) to the generic member. You'll need to provide some way to convert the string to type T -- usually through casting. For example:
this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
In this line:
this.value = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
you are setting your variable of type T to a string value. The RawValue method returns a string. You need to explicitly cast it to type T.
this.value = (T) (object) DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
Is T really only going to be only values without constructors? You might be able to make that explicit and avoid the object casting, if you want to avoid that for some reason.
Try a
string strValue = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue;
this.value = (T)Convert.ChangeType(strValue, typeof(T), CultureInfo.InvariantCulture)
if you have your configuration values stored as strings and want it converted to the right type. This only works for most of the primitive types like Int32, Double, etc.
How can I create a function that will have a dynamic return type based on the parameter type?
Like
protected DynamicType Test(DynamicType type)
{
return ;
}
You'd have to use generics for this. For example,
protected T Test<T>(T parameter)
{
}
In this example, the '<T>' tells the compiler that it represents the name of a type, but you don't know what that is in the context of creating this function. So you'd end up calling it like...
int foo;
int bar = Test<int>(foo);
Whilst the accepted answer is good, it has been over two years since it was written, so, I should add that you can use:
protected dynamic methodname(dynamic input)
{
return input;
}
Input will be returned as the same type, and you do not need to call the method as a generic.
Reference:
https://msdn.microsoft.com/en-us/library/dd264736.aspx
Actually, assuming that you have a known set of parameters and return types, it could be handled with simple overloading:
protected int Test(string p) { ... }
protected string Test(DateTime p ) { .... }
Then you need use generics.
protected T Test(T type) {
return type;
}
C# is not a dynamic language. To tackle this problem in C# you can return a generic object and typecast later to whatever you think the value should be -- not recommended. You can also return an interface, this way you don't really care about a specific class instance. As others have pointed out you can also use generics. It really depends on what you need / want to do inside the body of the function since all the methods above have their own limitations.
I want to make a method:
object Execute()
{
return type.InvokeMember(..);
}
to accept a generic parameter:
T Execute<T>()
{
return Execute() as T;
/* doesn't work:
The type parameter 'T' cannot be used with the 'as' operator because
it does not have a class type constraint nor a 'class' constraint */
// also neither typeof(T), nor T.GetType() are possible
return (T) Execute(); // ok
}
But I think operator as will be very useful: if result type isn't T method will return null, instead of an exception! Is it possible to do?
You need to add
where T : class
to your method declaration, e.g.
T Execute<T>() where T : class
{
By the way, as a suggestion, that generic wrapper doesn't really add much value. The caller can write:
MyClass c = whatever.Execute() as MyClass;
Or if they want to throw on fail:
MyClass c = (MyClass)whatever.Execute();
The generic wrapper method looks like this:
MyClass c = whatever.Execute<MyClass>();
All three versions have to specify exactly the same three entities, just in different orders, so none are any simpler or any more convenient, and yet the generic version hides what is happening, whereas the "raw" versions each make it clear whether there will be a throw or a null.
(This may be irrelevant to you if your example is simplified from your actual code).
You cannot use the as operator with a generic type with no restriction. Since the as operator uses null to represent that it was not of the type, you cannot use it on value types. If you want to use obj as T, T will have to be a reference type.
T Execute<T>() where T : class
{
return Execute() as T;
}
This small piece of code is an exception safe substitution for the as-keyword:
return Execute() is T value ? value : default(T)
It uses the pattern matching feature introduced with C# 7.
Use it, if you don't want to restrict the generic parameter to a reference type
It seems like you are just adding a wrapper method for casting to the type the user wants, thus only adding overhead to the execution. For the user, writing
int result = Execute<int>();
isn't much different from
int result = (int)Execute();
You can use the out modifier to write the result into a variable in the caller's scope, and return a boolean flag to tell whether it succeeded:
bool Execute<T>(out T result) where T : class
{
result = Execute() as T;
return result != null;
}
Is there a chance that Execute() might return a value type? If so, then you need Earwicker's method for class types, and another generic method for value types. Might look like this:
Nullable<T> ExecuteForValueType<T> where T : struct
The logic inside that method would say
object rawResult = Execute();
Then, you'd have to get the type of rawResult and see if it can be assigned to T:
Nullable<T> finalReturnValue = null;
Type theType = rawResult.GetType();
Type tType = typeof(T);
if(tType.IsAssignableFrom(theType))
{
finalReturnValue = tType;
}
return finalReturnValue;
Finally, make your original Execute message figure out which T is has (class or struct type), and call the appropriate implementation.
Note: This is from rough memory. I did this about a year ago and probably don't remember every detail. Still, I hope pointing you in the general direction helps.