Extension method for string array and params - c#

How can I get both these two methods to compile?
public static IEnumerable<string> DoSomething(params string[] args)
{ // do something }
public static IEnumerable<string> DoSomething(this string[] args)
{ // do something }
I get this compile error:
Type 'Extensions' already defines a member called 'DoSomething' with the same parameter types Extensions.cs
So that I can do this:
new string[] { "", "" }.DoSomething();
Extensions.DoSomething("", "");
Without the params method, I have to do this:
Extensions.DoSomething(new string[] { "", "" });
Update: Based on the answer by O. R. Mapper
public static IEnumerable<string> DoSomething(string arg, params string[] args)
{
// args null check is not required
string[] argscopy = new string[args.Length + 1];
argscopy[0] = arg;
Array.Copy(args, 0, argscopy, 1, args.Length);
return argscopy.DoSomething();
}
Update: I like HugoRune's answer now.

You can add an additional parameter to the params version:
public static IEnumerable<string> DoSomething(string firstArg, params string[] moreArgs)
That should be sufficient for the compiler to distinguish it from the string[] extension method.
As suggested by user SLaks, an additional overload without any arguments should be provided in this case, if the situation with an empty params array needs to be supported:
public static IEnumerable<string> DoSomething()

Late answer:
Another option is to just put both methods in different classes. Since you never us the class name when calling the extension method (the one with the this parameter), the extension method can be in any public static class in the same namespace, without any noticeable difference.
// contains static methods to help with strings
public static class StringTools
{
public static IEnumerable<string> DoSomething(params string[] args)
{
// do something
}
}
// contains only extension methods
public static class StringToolsExtensions
{
public static IEnumerable<string> DoSomething(this string[] args)
{
return StringTools.DoSomething(args);
}
}
This way you avoid copying the string array, you do not need an additional overload with no arguments, and I would say it looks cleaner. I would always separate extension methods and other static methods to avoid confusion.

You can give one of the two methods a different name. i.e. DoSomething2
You can just use one method. It's the same method with the same parameter list; clearly they're doing the same thing (since you didn't give them different names as per #1). Just combine them.
You can change the parameter list of one of the methods. i.e. (this string[] args, object unusedParameter)

Related

In C#, is there a way to pass an array to a method that takes in a variable length parameters?

Suppose I have this method I want to call, and it's from a third-party library so I cannot change its signature:
void PrintNames(params string[] names)
I'm writing this method that needs to call PrintNames:
void MyPrintNames(string[] myNames) {
// How do I call PrintNames with all the strings in myNames as the parameter?
}
I would try
PrintNames(myNames);
You would know if you had a look at the specs on MSDN: http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
They demonstrated it quite clearly - note the comment in the sample code:
// An array argument can be passed, as long as the array
// type matches the parameter type of the method being called.
Sure. The compiler will convert multiple parameters into an array, or just let you pass in an array directly.
public class Test
{
public static void Main()
{
var b = new string[] {"One", "Two", "Three"};
Console.WriteLine(Foo(b)); // Call Foo with an array
Console.WriteLine(Foo("Four", "Five")); // Call Foo with parameters
}
public static int Foo(params string[] test)
{
return test.Length;
}
}
Fiddle

Pass different methods as parameter to invoke by method name

I have several methods in a Util class with different return types and different parameters, f.e:
int RealMethodToExecute(int i, string s) { ... }
Those methods must be invoked in the ui thread and the call would look something like that:
int x = (int)InvokeControl.Invoke("Util.RealMethodToExecute");
Because in my opinion using the method names as string is not really pretty, i thought at the following solution:
public int WrappedRealMethodToExecute(int i, string s)
{
return InvokeMethod(Util.RealMethodToExecute, i, s);
}
private static T InvokeMethod<T>(Func<int, string, T> func, params object[] p)
{
return (T)InvokeControl.Invoke(func.Method.DeclaringType.FullName + "." + func.Method.Name, p);
}
The problem now is that InvokeMethod only acceppts methods with an int and a string parameter and a return value but i have different methods which i want to execute.
I dont want to overload InvokeMethod. I just need the full qualified name of the function to execute it.
Any ideas??
edit: extended example with parameters
Fankly, this might as well be just:
private static object InvokeMethod(Delegate method, params object[] args)
{
return InvokeControl.Invoke(method, args);
}
where InvokeControl.Invoke uses (to get to the UI thread):
someControl.Invoke(method, args);

Extension method on string[] to lowercase all elements?

Consider the following method example:
public static string[] ParseOptions()
{
return Environment.GetCommandLineArgs();
}
What would I have to do to create an extension that would make ParseOptions() return all command line arguments in lower case?
I would like to be able to use the extension as follows:
var argArray = ParseOptions().MyExtToLower();
Note: I'm asking this to better understand how to create an extension for a method. I'm not actually interested in getting lower case command line arguments this way.
public static string[] MyExtToLower(this string[] source)
{
for (int i = 0; i < source.Length; i++)
{
source[i] = source[i].ToLower();
}
return source;
}
Notice the this keyword in the parameter list. That is what makes it possible to call the method like this:
var argArray = ParseOptions().MyExtToLower();
To be clear, you're not actually adding an extension to a method here. What you are doing is adding an extension to the type that the method returns.
You seem to be talking about Fluent Interfaces. Look at this example - http://blog.raffaeu.com/archive/2010/06/26/how-to-write-fluent-interface-with-c-and-lambda.aspx
Or, you can create extension methods on the type you are returning ( in your case, string[] ) to get the method chaining - http://msdn.microsoft.com/en-us/library/bb383977.aspx
For the syntax you describe you would have to extend String[] or possibly IEnumerable<String> the following way:
public static class MyExtensions {
public static String[] MyExtToLower(this String[] strings) {
return strings.Select(s => s.toLower()).ToArray();
}
public static IEnumerable<String> MyExtToLower(this IEnumerable<String> strings) {
return strings.Select(s => s.toLower());
}
}
You don't create extension of methods, you create methods which extend objects' capabilities. Those methods must be static and part of a static class. They must have one parameter marked with the this keyword to indicate which object you want to extend. In your case, you must write something like:
// the class must be static, I usually declare a class reserved for extension method.
// I mark it as partial so that I can put every method in the same file where I use it.
public static partial class Extension {
// This is the extension method; it must be static. Note the 'this' keyword before
// the first parameter: it tells the compiler extends the string[] type.
public static MyExtToLower( this string[ ] args ) {
// your code
}
}
Note that you cannot override instance method. Altough you can have a method with the same signature as an instance method that method will be never called due to the way the compiler binds to.

How to create an extension method for ToString?

I have tried this:
public static class ListHelper
{
public static string ToString<T>(this IList<String> list)
{
return string.Join(", ", list.ToArray());
}
public static string ToString<T>(this String[] array)
{
return string.Join(", ", array);
}
}
But it does not work, both for string[] and List<string>. Maybe I need some special annotations?
Extension methods are only checked if there are no applicable candidate methods that match. In the case of a call to ToString() there will always be an applicable candidate method, namely, the ToString() on object. The purpose of extension methods is to extend the set of methods available on a type, not to override existing methods; that's why they're called "extension methods". If you want to override an existing method then you'll have to make an overriding method.
It sounds like you want to replace what files.ToString() returns. You will not be able to do that without writing a custom class to assign files as (i.e. inherit from List and override ToString().)
First, get rid of the generic type (<T>), you're not using it. Next, you will need to rename the extension method because calling files.ToString()will just call the List's ToString method.
This does what you're looking for.
static class Program
{
static void Main()
{
var list = new List<string> { {"a"}, {"b"}, {"c"} };
string str = list.ToStringExtended();
}
}
public static class ListHelper
{
public static string ToStringExtended(this IList<String> list)
{
return string.Join(", ", list.ToArray());
}
}
Simply you Shouldn't use the name ToString for the Extension method as it will never be called because that method already exist and you shouldn't use T as its useless there.
For example i tried this and again it returned same thing:
Console.WriteLine(lst.ToString<int>());
output:
shekhar, shekhar, shekhar, shekhar
so this time i used int and it still ran because that T has no use other then changing the Method Prototype.
So simply why are you using ToString Literal as Method name, as it already exist and you can't override it in a Extension method, this is the reason you had to use that T to make it generic. Use some different name like
public static string ToMyString(this IList<String> list)
That way you wouldn't have to use generic as it useless there and you could simply call it as always.
That said your code is working for me. here is what i tried (in LINQPAD):
void Main()
{
List<string> lst = new List<string>();
lst.Add("shekhar");
lst.Add("shekhar");
lst.Add("shekhar");
lst.Add("shekhar");
lst.ToString<string>().Dump();
}
public static class ListHelper
{
public static string ToString<T>(this IList<String> list)
{
return string.Join(", ", list.ToArray());
}
public static string ToString<T>(this String[] array)
{
return string.Join(", ", array);
}
}
And the output was shekhar, shekhar, shekhar, shekhar
Since you have specified that T in ToString<T> you will need to mention a Type like string or int while calling the ToString method.

Is it a bad idea to use params [] in method signature

Consider the following class
public class PlanetKrypton
{
public static void CallSuperManforHelp(string helpMessage, params object[] kryptonParams)
{
Console.WriteLine(String.Format(helpMessage,kryptonParams));
}
public static void CallSuperManforHelp(string helpMessage ,string sender,string senderZipCode)
{
Console.WriteLine("{0} from {1}. I am {2}", helpMessage, sender, senderZipCode);
}
}
public class ConsoleMan
{
public static void Main(string[] args)
{
string helpMessage = "I have a flat tire";
string sender = "Jerry";
int wrongZipType = 12345;
PlanetKrypton.CallSuperManforHelp(helpMessage, sender, wrongZipType);
PlanetKrypton.CallSuperManforHelp(helpMessage);
}
}
Now, if I have a more strongly typed method signature in the first method, I would have gotten a compile time error for both these method calls.
Are there any "best practices" for using params in method signature ?
Edit:Am making this a community wiki
I rarely see a need for it, myself.
If my function might need a collection of items, I make it take exactly that: ICollection<> or IEnumerable<>, potentially with an overload that takes a single T for that special case.
If the function is more utilitarian in nature (for example, I have a generic multi-field HashCode generating function), where params might seem to fit, I will still provide quite a few overloads for specific cases like 1 arg, 2 args, 3 args ... sometimes to 5 args or 10 args. Then I will add a catch-all with params. I do this because of the array object creation implicit with params.
I would avoid using params[] object. What I would do is create a class that encapsulates the three strings in your second overload:
public class HelpStuff
{
public string Message{get;set;}
public string Help{get;set;}
public string ZipCode{get;set;}
}
Then have two overloads like this:
public static void CallSuperManforHelp(string helpMessage, params string[] kryptonParams)
{
//do work
}
public static void CallSuperManforHelp(HelpStuff helpStuff)
{
//do work
}
Well, the obvious thing is that compile time errors are better than runtime errors. However, a flexible, usable API sometimes has to take precedence. I'd say in general you should only use arrays of Object, which lack compile time type safety and are sometimes inefficient, if you're sure there's no more static way to accomplish what you want.
If you have this method:
public static void CallSuperManforHelp(string helpMessage, params object[] kryptonParams) { ... }
you can cool it with these code:
CallSuperManforHelp("please help");
CallSuperManforHelp("please help", (object[])null);
These calling are equivalent. So if you overloading the "CallSuperManforHelp", you should think about calling convenction of these methods.
It's rarely needed, but useful at times - so I wouldn't say it's a best practice to avoid it. Just try to avoid ambiguity.
String.Format is of course the canonical example, and most cases where I use params, it's to pass to String.Format (e.g. a logging method).
Another example from the framework is DataRowCollection.Add: it's useful to be able to add field values without building an object array first:
DataTable myDataTable;
...
for(...)
{
myDataTable.Rows.Add(col1Value, col2Value, col3Value);
}
I wouldn't mix params/regular overloads in that way - I'd only generally use params to add an override that takes additional (unknown at compile time) parameters.
e.g. A normal method, and then one that takes an additional params:
public static void CallSuperManforHelp(string helpMessage);
public static void CallSuperManforHelp(string helpMessage, params object[] kryptonParams);
This eliminates the ambiguity between the overloads.
If you want the two methods you have defined, then you could simply give them different names to avoid any ambiguity and clarify their usage:
public static void CallSuperManforHelpFormatted(string helpMessage, params object[] kryptonParams)
public static void CallSuperManforHelp(string helpMessage ,string sender,string senderZipCode)

Categories