Extension method on string[] to lowercase all elements? - c#

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.

Related

Why is my extension method not working?

I have an extension method
public static class DbMigratorExtensions
{
public static IEnumerable<string> DoCoolStuff(this DbMigrator dbMigrator, string[] first, string[] second)
{
// ...
}
}
and I'm trying to use it like
DbMigrator.DoCoolStuff
but I get the
'DbMigrator' does not contain a definition for ...
I have followed all the bullet points on
Why is my Extension Method not showing up in my test class?
Also I will note that VS recognizes
DbMigratorExtensions.DoCoolStuff
so I'm not sure why it isn't working as an extension method.
Extension methods work on object instances, not types.
So you need to change
DbMigrator.DoCoolStuff(...);
to
var migrator = new DbMigrator();
var stringList = migrator.DoCoolStuff(...);
If DoCoolStuff() doesn't need an instance, it should not be an extension method.
If what you want is a static extension method, C# does not currently support this. You can only make non-static extension methods. This will probably change at some point.

Why am I allowed to pass in more parameters than I defined for the method?

I'm trying to learn a mobile development framework called Xamarin that uses C#, which I am a beginner at as well. I was following a tutorial when I came across the following code:
public static class PhonewordTranslator
{
public static string ToNumber(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
return "";
}
else
{
raw = raw.ToUpper();
}
var newNumber = new StringBuilder();
foreach (var c in raw)
{
if (" -0123456789".Contains(c))
{
newNumber.Append(c);
}
else
{
var result = TranslateToNumber(c);
if (result != null)
{
newNumber.Append(result);
}
}
}
return newNumber.ToString();
}
static bool Contains (this string keyString, char c)
{
return keyString.IndexOf(c) >= 0;
}
static int? TranslateToNumber(char c)
{
if ("ABC".Contains(c))
return 2;
else if ("DEF".Contains(c))
return 3;
else if ("GHI".Contains(c))
return 4;
else if ("JKL".Contains(c))
return 5;
else if ("MNO".Contains(c))
return 6;
else if ("PQRS".Contains(c))
return 7;
else if ("TUV".Contains(c))
return 8;
else if ("WXYZ".Contains(c))
return 9;
return null;
}
Why am I allowed to pass in a single parameter to the Contains() method even though it clearly has two parameters. What is the purpose of this?
The Contains() method is whats known as an extension method. You can find more information about them here.
In your code Contains method is defined as Extension Method.
So what are Extension Methods
Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type.
And how they work?
Extension methods are defined as static methods but are called by using instance method syntax. Their first parameter specifies which type the method operates on, and the parameter is preceded by the this modifier.
In your code you invoke the extension method with instance method syntax. However, the intermediate language (IL) generated by the compiler translates your code into a call on the static method.
Lets understand this with an example.
As you all know if we convert an object which is null to string by calling ToString method then it throws NullReferenceException. Though I can call Convert.ToString() method which doesn't throw exception for null value. But what if I want to stick ToString method like syntax. So before calling ToString method on any object that need to be converted to stringvalue, First i need to check for null and then convert it to string value. But it is time consuming and i have to write code for it.
To overcome this i have created a ExtensionMethod named as ToStringNullSafe. It is going to first check for null value of object. If it has null value then it will convert it to an Empty String otherwise converts object value to a string value.
This is the definition of the my Extension method
public static string ToStringNullSafe(this object obj)
{
return (obj ?? string.Empty).ToString();
}
And this is the calling syntax
DataRow dr = dataTable.Rows[0];
string firstName = dr["firstName"].ToStringNullSafe();
One thing need to consider while creating a ExtensionMethod is that ExtentionMethod name should differ from the method present in .Net framework. Like we have ToString method for string conversion. So i can't create a extension method with this name.
What if i create an extension method with name as of .Net framework method name then there will not be compiler errors but your created ExtensionMethod will not be called. Suppose if i create an extension method by defining its name as ToString then compiler will not invoke my extension method. It will invoke ToString method provided by .Net framework.
In visual studio a Down Arrow sign appears for ExtensionMethos
Extension Methods can be placed in separate class like i have an Extension Method to convert a DataTable to string[][] array in a separate class.
namespace myProject.Common
{
public static class ExtensionMethods
{
public static object ToStringArray(this DataTable dt, params string[] columns)
{
//AsEnumerable is also a Extension Method provided by .Net framework.
return dt.AsEnumerable().Select(x => columns.Select(c => x[c].ToStringNullSafe()).ToArray()).ToArray();
}
}
public static string ToStringNullSafe(this object obj)
{
return (obj ?? string.Empty).ToString();
}
}
To use this ExtensionMethod in my project, i have to add an using statement first
using myProject.Common;
then i can call this method as follow:
var dataTableData = dataTable.ToStringArray("firstName", "LastName", "Age", "Email");
Another syntax of calling extension method is;
var dataTableData = ExtensionMethods.ToStringArray(dataTable,"firstName", "LastName", "Age", "Email");
Further Reading:
Extension
Methods
Creating an extension method for ToString?
Advantages of Extension Methods
Disadvantages of extension methods

What is the difference between generic method and generic extension method and extension method?

What is the difference between generic method and generic extension method and extension method?
Generic method by MSDN.
A generic method is a method that is declared with type parameters
static void Swap<T>(ref T lhs, ref T rhs)
{
T temp;
temp = lhs;
lhs = rhs;
rhs = temp;
}
This method swaps the references between lhs (left-hand-side) and rhs (right-hand-side). Because we only want to swap the references and don't care about what the underlying types of the references are, we can declare the method as a generic method with type parameter T. This means it can be of any type. This saves us from having to write multiple Swap methods.
string s1 = "hello";
string s2 = "world";
Swap(ref s1, ref s2);
int i1 = 5;
int i2 = 12;
Swap(ref i1, ref i2);
While the example could be written using object types as Swap method parameters, this would cause an unnecessary overhead with value types known as boxing.
Extension method by MSDN
Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type.
Let's say we want to extend the existing string class to contain a method for counting words in the string.
public static int WordCount(this String str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
Now we can count words from any string object.
string s = "Hello Extension Methods";
int i = s.WordCount();
This is especially useful for adding features (methods) to existing classes which you do not have access to (from third party assembly, for example).
Generic extension methods are simply a mix of the previous two concepts.
generic method is called just like regular method, with the difference it can be used for different types by specifying generic type.
someObject.GenericMethodFromSameClass<String>();
generic extension method and extension method are similar to each other in a sense that they can be called on objects they extend. Difference between them is the same as difference between regular method and generic method.
someObject.ExtensionMethodFromOtherClass();
someObject.GenericExtensionMethodFromOtherClass<String>();
• Extension Method:
With extension method can add some extra method to specified type.
For create extension method
Definition class with public static attribute.
Definition method in class with public static attribute.
For first parameter of method defined extension method .place before this parameter keyword this.
public static class TestExtensionClass
{
public static string TestExtinsionMethod(this string password)
{
string encriptedPassword="";
byte[] ASCIIValues = Encoding.ASCII.GetBytes(password);
foreach (byte b in ASCIIValues)
{
encriptedPassword += b.ToString();
}
return encriptedPassword;
}
}
In other classes call extension method.
private void CallExtensionMethod()
{
string s = "123";
s.TestExtinsionMethod();
}
• Generic Method:
With generic method you can define output type in runtime.
For create extension method
Definition class.
Definition method. Before name of method place T.
After name of method place <**T>**.
public T TestCastTo<T>(object obj)
{
return (T)obj;
}
In other classes call Generic method.
public static T TestCastTo<T>(this object obj)
{
return (T)obj;
}
• Generic Extension Method:
• With combine properties Extension Method and Generic Method you can gain a Generic Extension Method.
public static T TestCastTo<T>(this object obj)
{
return (T)obj;
}
in other class call generic extension method
private void CallGenericExtensionMethod()
{
string s = "123";
int i = s.TestCastTo<int>();
}
Methods can be generic or nongeneric, for example:
public void Foo() { } // Non-Generic Method
public void Foo<T>(T value) { } // Generic Method
Extension methods are methods used to extend the behavior of types without modifying the type itself. Say you want the String type to have a Reverse method, you could define an extension method on the String type, like this:
public static class ExtMethods
{
public static string Reverse(this string s) // Non-Generic Extension Method
{
// code to reverse string
}
}
Extension methods must be declared static and within a static class, also its first parameter must have this before the type it extends.
Likewise, extension methods can be generic:
public static class ExtMethods
{
public static Foo<T>(this T obj) // Generic extension method
{
}
}
So, a Generic Extension Method is just an extension method that happens to be generic.

Extension method for string array and params

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)

How do I override ToString() and implement generic?

I have code that I want to make the following changes:
How do I override ToString()? It says: A static member ...ToString(System.Collections.Generic.List)' cannot be marked as override, virtual, or abstract.
How do I make it generic?
public static override string ToString(this List<int> list) {
string output = "";
list.ForEach(item => output += item.ToString() + "," );
return output;
}
Thanks!
You cannot use extension methods to override an existing method.
From the spec http://msdn.microsoft.com/en-us/library/bb383977.aspx
"You can use extension methods to extend a class or interface, but not to override them. An extension method with the same name and signature as an interface or class method will never be called. At compile time, extension methods always have lower priority than instance methods defined in the type itself."
If you want to override ToString(), you would need to inherit from List<T> rather than try to extend it. You have already seen that you cannot mark the static extension method as override, and overload resolution will always go for the member method over an extension method if it is available. Your options are
Inherit and override
Change your extension method's name to something else ToSpecialString()
Call the method directly using the class name MyExtensions.ToString(myList);
What are you trying to achieve? Often I want to output the contents of a list, so I created the following extension method:
public static string Join(this IEnumerable<string> strings, string seperator)
{
return string.Join(seperator, strings.ToArray());
}
It is then consumed like this
var output = list.Select(a.ToString()).Join(",");
EDIT: To make it easier to use for non string lists, here is another variation of above
public static String Join<T>(this IEnumerable<T> enumerable, string seperator)
{
var nullRepresentation = "";
var enumerableAsStrings = enumerable.Select(a => a == null ? nullRepresentation : a.ToString()).ToArray();
return string.Join(seperator, enumerableAsStrings);
}
public static String Join<T>(this IEnumerable<T> enumerable)
{
return enumerable.Join(",");
}
Now you can consume it like this
int[] list = {1,2,3,4};
Console.WriteLine(list.Join()); // 1,2,3,4
Console.WriteLine(list.Join(", ")); // 1, 2, 3, 4
Console.WriteLine(list.Select(a=>a+".0").Join()); // 1.0, 2.0, 3.0, 4.0
You can only override a method if you inherit the base class.
What I would advocate is calling your extension method .ToCsv().

Categories