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());
Related
I want to do all of the same code twice, but just for two different objects. I am getting these objects from a SOAP API (rather outdated one).
I want to avoid writing duplicate code over and over again. I'll be taking my original object and manipulating it a lot (all the same way) the only difference is that the object type is the difference, so that's why I need to make a generic object. I want it to return the same type as it takes as a parameter. I am having an issue that if I do code like this
public static class ParamsHelper<T>
{
public static async Task<T[]> Whatever(T[] rptParams)
{
//do some stuff to rptparams
return rptParams;
}
}
// then I call it like this below:
var params = await ParamsHelper.Whatever<ItemP[]>(new ItemP[]{});
// it says can't convert type ItemP[] to type ItemP[][].
Additionally, I am using LINQ to do all of the manipulating. I would love advice on how to access the object fields (maybe reflection?)
You have to declare the generic type on the method.
public static async Task<T[]> Whatever<T>(T[] rptParams)
The usage generally is implied from usage so you don't have to pass it.
if you do have to pass it, dont make it an array.
ParamsHelper.Whatever<ItemP>(new ItemP[] { });
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.
I'm retrieving a list of methods from a class
foreach (MethodInfo item in typeof(RptInfo).GetMethods())
{
if (item.ReturnType.Equals(typeof(DataTable)))
{
lstMethods.Items.Add((item.Name));
}
}
Clearly adding the method names to a list control.
I'm having problem, I guess more correctly, not understanding, the proper use of 'Action or 'Func' in order to call the selected method name and getting it's return value into a dataview control.
I did reference:
How to call a Method from String using c#?
but still not certain as to a correct implementation method. Still new to implementing these concepts
First, note that the typeof(RptInfo).GetMethods() will give you both instance and static methods, with any number of parameters. To call any of these methods, you'll need to supply the instance (unless the method is static), and values for the parameters. I suggest you look into overloads of the GetMethods method if you want to get methods only with specific signatures.
Let's say you have an instance of the RptInfo on which you want to run your methods, and you have enough values to provide for their parameters. Then, when you select your item from the list, you should call something like
DataTable result = typeof(RptInfo)
.GetMethod(lstMethods.SelectedItem.ToString())
.Invoke(instance, new object[]{value1,value2})
as DataTable
Again, look into overloads of the GetMethod method in case you might have methods with the same name but different signatures. In the Invoke call, you'll use null instead of the instance if your method is static, and you will have to provide the proper number of properly typed values to satisfy the method's signature.
This must be a duplicate but i haven't found it. I've found this question which is related since it answers why it's recommended to use a method group instead of a lambda.
But how do i use an existing method group instead of a lambda if the method is not in the current class and the method is not static?
Say i have a list of ints which i want to convert to strings, i can use List.ConvertAll, but i need to pass a Converter<int, string> to it:
List<int> ints = new List<int> { 1 };
List<string> strings = ints.ConvertAll<string>(i => i.ToString());
This works, but it creates an unnecessary anonymous method with the lambda. So if Int32.ToString would be static and would take an int i could write:
List<string> strings = ints.ConvertAll<string>(Int32.ToString);
But that doesn't compile - of course. So how can i use a method group anyway?
If i'd create an instance method like this
string FooInt(int foo)
{
return foo.ToString();
}
i could use strings = ints.ConvertAll<string>(FooInt);, but that is not what i want. I don't want to create a new method just to be able to use an existing.
There is an static method in the framework, that can be used to convert any integrated data type into a string, namely Convert.ToString:
List<int> ints = new List<int> { 1 };
List<string> strings = ints.ConvertAll<string>(Convert.ToString);
Since the signature of Convert.ToString is also known, you can even eliminate the explicit target type parameter:
var strings = ints.ConvertAll(Convert.ToString);
This works. However, I'd also prefer the lambda-expression, even if ReSharper tells you something different. ReSharper sometimes optimizes too much imho. It prevents developers from thinking about their code, especially in the aspect of readability.
Update
Based on Tim's comment, I will try to explain the difference between lambda and static method group calls in this particular case. Therefor, I first took a look into the mscorlib disassembly to figure out, how int-to-string conversion exactly works. The Int32.ToString method calls an external method within the Number-class of the System namespace:
[__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), SecuritySafeCritical]
public string ToString(IFormatProvider provider)
{
return Number.FormatInt32(this, null, NumberFormatInfo.GetInstance(provider));
}
The static Convert.ToString member does nothing else than calling ToString on the parameter:
[__DynamicallyInvokable]
public static string ToString(int value)
{
return value.ToString(CultureInfo.CurrentCulture);
}
Technically there would be no difference, if you'd write your own static member or extension, like you did in your question. So what's the difference between those two lines?
ints.ConvertAll<string>(i => i.ToString());
ints.ConvertAll(Convert.ToString);
Also - technically - there is no difference. The first example create's an anonymous method, that returns a string and accepts an integer. Using the integer's instance, it calls it's member ToString. The second one does the same, with the exception that the method is not anonymous, but an integrated member of the framework.
The only difference is that the second line is shorter and saves the compiler a few operations.
But why can't you call the non-static ToString directly?
Let's take a look into the ConvertAll-method of List:
public List<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter)
{
if (converter == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.converter);
}
List<TOutput> list = new List<TOutput>(this._size);
for (int i = 0; i < this._size; i++)
{
list._items[i] = converter(this._items[i]);
}
list._size = this._size;
return list;
}
The list iteraterates over each item, calls the converter with the item as an argument and copys the result into a new list which it returns in the end.
So the only relation here is your converter that get's called explicitly. If you could pass Int32.ToString to the method, the compiler would have to decide to call this._items[i].ToString() within the loop. In this specific case it would work, but that's "too much intelligence" for the compiler. The type system does not support such code conversions. Instead the converter is an object, describing a method that can be called from the scope of the callee. Either this is an existing static method, like Convert.ToString, or an anonymous expression, like your lambda.
What causes the differences in your benchmark results?
That's hard to guess. I can imagine two factors:
Evaluating lambdas may result in runtime-overhead.
Framework calls may be optimized.
The last point especially means, that the JITer is able to inline the call which results in a better performance. However, those are just assumptions of mine. If anyone could clarify this, I'd appreciate it! :)
You hit the nail on the head yourself:
This works, but it creates an unnecessary anonymous method with the
lambda.
You can't do what you're asking for because there is no appropriate method group that you can use so the anonymous method is necessary. It works in that other case because the implicit range variable is passed to the delegate created by the method group. In your case, you need the method to be called on the range variable. It's a completely different scenario.
I'm trying to do this:
public void CustomMethod(params int[] number,params string[] names)
{
...
}
If i delete one of them , there is no problems , any idea of why i can't do this?
I have tried putting a normal parametre in the middle of both.
Only the last parameter can have params. See the documentation.
No additional parameters are permitted after the params keyword in a method declaration, and only one params keyword is permitted in a method declaration.
The reason is that allowing multiple params would give ambiguity. For example, what would this mean?
public void CustomMethod(params int[] foo, params int[] bar)
{
...
}
// ...
CustomMethod(1, 2);
This is simply not supported. The compiler can't know when one parameter list ends and the next begins.
As far as I know, you can only write one params parameter in the constructor which shall be the last parameter of the constructor.
The params keyword lets you specify a method parameter that takes an argument where the number of arguments is variable.
No additional parameters are permitted after the params keyword in a method declaration, and only one params keyword is permitted in a method declaration.
See Here : http://msdn.microsoft.com/en-us/library/w5zay9db(v=VS.71).aspx