I'm working on a code base with multiple services that get Timeout Exceptions.
My idea was to create a generic method that takes in a service method as parameter and returns the method call.
My issue is that when I call this method and pass in a method that returns a list of int I get an error because it can't convert from system.collections.generic.list... to system.func.system.collections.generic.list...
I found a post which was trying to convert accordingly, but I don't wish to convert. I simply want the list of strings, not the function that gives me a list of strings. I'm not quite sure where to go from here?
private U HandleTimeoutException<U>(Func<U> fn)
{
U result = default(U);
try
{
result = fn();
}
catch (TimeoutException)
{
//some code that handles the exception
};
return result;
}
edit:
My method call is :
HandleTimeoutException<List<id>>(getListofIds(fName,lName,regionId));
I think that c# won't let me pass the method signature as parameter because the signature itself has 3 parameters, or because it evaluates the method and think it's getting a list of Id's as parameter. Is there anyway I can use a delegate to call getListofIds(X,Y,Z) and pass that delegate to my generic try/catch function?
Thanks for any advice!
What you're doing is not passing a function to HandleTimeoutException, but passing the result of getListofIds method.
This will fix it:
HandleTimeoutException(() => getListofIds(fName, lName, regionId));
Notice: you don't even have to specify the template argument type.
Related
I have a generic function as follows:
public static T Function<T>(Argument arg)
{
//DO FUNCTION STUFF
}
I want to call this function using a Type I get from FieldInfo.FieldType like so:
Function<someFieldInfo.FieldType>(arg);
However, this is not allowed. And neither is:
Function<typeof(SomeType)>(arg);
I am far from a C# expert so excuse if this is a stupid question. But why doesn't this work? And how can I work around it to get similar functionality?
Since you can't accept a comment as an answer I just thought I would write it hear.
First Question: Why can't you pass the Type you get from fieldInfoInstance.FieldType to a generic function
If I have understood everything correctly, it is as #Lee pointed out, what is returned from fieldInfoInstance.fieldType is an instance of a class that extends type where as a generic function expects a Type Paramater.
Second Question: How can you work around not being able to do so?
I ended up doing like #silkfire and #Lee suggested, having a function that takes the type as an argument instead of an generic function. However I still prefer generic functions over casting when using a function so I ended up using two functions.
private static object Function(Type type, Arguments args)
{
// DO FUNCTION STUFF
}
and
public static T Function<T>(Arguments args)
{
return (T) Function(typeof(T), args);
}
This way the user can still call the function in a generic way, and by doing so doesn't have to cast the returned object (In my opinion alot cleaner) and I can call the function and pass in a Type. The non-generic function doesn't have to be public because the only time I need to pass the Type using a Type Instance instead of a Type Parameter is when recursively calling the function from within.
You can tell the compiler to force T to be the same as someFieldInfo.Field by passing in an expression (which is never used)
public static T Function<T>(Argument arg, Expression<Func<T>> anyField)
{
}
T result = Function(arg, () => someFieldInfo.Field);
But that's at compile-time. Generic types in C# have to be resolved at compile-time.
You wanted to use somefieldInfo.FieldType at run-time. For run-time types you cannot use generics, because you cannot predict what the type will be.
Instead cast the returned object at run-time using Convert.ChangeType.
public static object Function(Argument arg, Type anyFieldType)
{
object result = ...;
return Convert.ChangeType(result, anyFieldType);
}
object result = Function(arg, someFieldInfo.FieldType);
Say you have this generic method:
public static T ConvertValue<T, U>(U value) where U : IConvertible
{
return (T)Convert.ChangeType(value, typeof(T));
}
If I want to call this method inside another generic method. The outer generic method must receive as arguments the actual argument values to set <T, U>(U value) of the inner generic method.
How to achieve this properly, so that I can call OuterGeneric and feed it with the appropriate arguments?
This is just a demonstration of how I need to use it.
public void OuterGeneric<TypeT, TypeU>(TypeT tType, TypeU uType, TypeU valueOfTypeU)
{
// Call of Generic method
TypeT recieverOf_T = ConvertValue<tType, uType>(valueOfTypeU);
}
// Some way to call OuterGeneric. How?
Just call ChangeType directly. You're wrapping the call in a method that requires the type to be specified at compile time, rather than runtime, and then asking how to call it when the type is only known at runtime. You already had a method (ChangeType) that does exactly that.
You don't need method parameters for the generic types in your outer method. You should be able to just use the type parameters like this:
public void OuterGeneric<TypeT, TypeU>(TypeU valueOfTypeU)
{
// Call of Generic method
TypeT recieverOf_T = ConvertValue<TypeT, TypeU>(valueOfTypeU);
}
Then call OuterGeneric the way you would any other generic method.
Your question is a little unclear because you used the term "dynamically." Of course generic parameters must be known at compile time, so if you're looking for a way to use generic methods when only knowing the types at runtime, then you don't actually want to use .NET generics.
I have a method that takes params and I want to provide those params with another method. Example:
public void Process(params string[] words)
{
// do some stuff
}
public IEnumerable<string> GetWords()
{
yield return "test";
}
Process(GetWords()); // Error collection of strings must be passed individually
However this is not allowed because the result is considered a single parameter of type IEnumerable instead of a set of parameters type string. I've tried using ToArray and ToList, same problem. Is there a way to use the result of a method as params argument?
Edit: The problem occurs when you pass another argument first. The problem is I need to keep access to the first parameter but not the others. That can be done by letting the method create all parameters, calling it separately and keeping a reference to the first element.
I think you want
Process(GetWords().ToArray());
I want to write a wrapper for the System.Web.Caching.Cache, which handles my cache requests.
I need a method, which can invoke a callback method, if the cache entry doesn't exist. The problem is: I dont know how many params the callback method has:
public T Get<T, TCallback>(string key, TCallback func) where TCallback : Func<T>
{
// check cachekey, do sth
T result = func.Invoke();
return result;
}
With this implementation it's possible to give a callback without params. But what if I have some?
Thanks,
trial
This method should only accept the parameters that this implementation wants to send to a given function. If it has no information that would be relevant to such a callback then it should simply require a parameter-less delegate. If it has parameters that will be needed for some, but won't be needed for others, it should provide them in all cases, using a single delegate.
It then becomes the responsibility of the caller to match the function that they want to call with the signature of the delegate. If they want to fix values for some function that has parameters your callback doesn't have, or if they want to call a function with less parameters, etc. it is their responsibility to make the "conversion", rather than this method's responsibility to deal with a delegate with an unknown signature.
The use of lambdas makes "converting" functions very easy; much easier than the alternative. To fix a value for a parameter when your callback doesn't have one, you can close over the variable:
int value = 5;
Get("key", () => SomeMethod(value));
You can also use a lambda to ignore a parameter:
Get("key", someParameterToIgnore => AnotherMethod());
1) You can use dynamic or Dictionary as parameter of your callback. Put in Dictionary or dynamic string value - like CallbackType.
Its bad because you lost static type analysing, but it possible.
2)It may be useful: Ellipsis notation in C#?
I have a situation like this:
public static SqlDataReader ReadFromDB(string inputSQLStatement)
{
//Does some actual work here ..
}
public static DataTable ReadFromDB(string inputSQLStatement)
{
return new DataTable().Load(ReadFromDB(inputSQLStatement));
}
basically the second function is trying to call another function with the same name as the calling function, but has a different return type ..
But with the above code, I get the following error on the return line in the second function:
The call is ambiguous between the following methods or properties ...
I thought maybe the compiler can figure out that the return from the second function is doing into a function which takes an SqlDataReader object, so it knows it has to call the version of ReadFromDB(), but I think I need to explicitly specify which version to call explicitly ..
So how can I tackle this ?
EDIT:
Nevermind, I found out my answer. Function overloading by return type is not supported in C#: http://msdn.microsoft.com/en-us/library/aa691131(v=vs.71).aspx
Overloading by return type is not supported as the formal signature of a method doesn't include the return type but only the name of the method and the types of the parameters (Thanks to CAbbot). See here for more info.
In this case you need to name the methods differently, for example:
public static SqlDataReader ReadFromDB(string inputSQLStatement)
{
//Does some actual work here ..
}
public static DataTable ReadDataTableFromDB(string inputSQLStatement)
{
return new DataTable().Load(ReadFromDB(inputSQLStatement));
}
The method signature is unique by its name, parameters length, then if the length is the same, then by their types (and when params is used, there is another situation). The idea is the return of the method does not count into the method signature.
So you will to rename the method, possible:
ReadFromDBIntoTable
The return value does not belong to the signature. You could give the methods different names, like ReadDataTableFromDB, or move them to interfaces that you explicitly implement.