Can I use inheritance with an extension method? - c#

I have the following:
public static class CityStatusExt
{
public static string D2(this CityStatus key)
{
return ((int) key).ToString("D2");
}
public static class CityTypeExt
{
public static string D2(this CityType key)
{
return ((int) key).ToString("D2");
}
Plus other classes with similar extensions that return the key formatted as a "D2"
Is there a way I could inherit from a base class and have the base class provide the functionality so
don't I don't have to repeat the same extension method code?
Update. I am sorry I did not mention this but my classes like CityType are Enums.

You can make the method generic. C# will infer the type:
public static class Extension
{
public static string D2<T> (this T key)
{
return ((int)(object) key).ToString("D2");
}
}

From the comment below, CityType and CityStatus are enums. Therefore you can do this:
public static class Extensions
{
public static string D2(this Enum key)
{
return Convert.ToInt32(key).ToString("D2");
}
}
Original answer:
You can use a generic method and an interface ID2Able:
public static class Extensions
{
public static string D2<T>(this T key) where T : ID2Able
{
return ((int) key).ToString("D2");
}
}
This way the extension method won't show up for absolutely every type; it'll only be available for things you inherit ID2Able from.

Your enums already all inherit from a common base class, namely System.Enum. So you can do this (Enums don't accept "D2" as a format string, but they accept "D", so I added a call to PadLeft):
public static class EnumExtensions
{
public static string D2(this Enum e)
{
return e.ToString("D").PadLeft(2, '0');
}
}

Related

How do I use an extension function in another class? C#

I've got a couple of extension functions that I want to transfer between classes.
I have a class called Helpers.cs that I want to have the following:
namespace XYZ
{
public class Helpers
{
public static string Encrypt(this string plainText){
//... do encrypting
}
}
}
In my other class Impliment.cs I want to have the following:
string s = "attack";
s.Encrypt();
How can I implement this?
You're close - extension methods need to be in a static class:
public static class Helpers
{
public static string Encrypt(this string plainText){
//... do encrypting
}
}
If you tried what you posted you'd get a pretty clear compiler error that says basically the same thing:
Extension method must be defined in a non-generic static class
Note that your usage will be slightly different that what you want. You can't do:
string s = "attack";
s.Encrypt();
becasue strings are immutable. Best you can do is overwrite the existing varialbe or store the result in a new one:
string s = "attack";
s = s.Encrypt(); // overwrite
or
string s = "attack";
string s2 = s.Encrypt(); // new variable
You need to make the class, static as well and use a using statement.
Example
FileA.cs:
namespace XYZ {
public static class Helpers {
public static string Encrypt(this string plainText){
//... do encrypting
return plainText;
}
}
}
FileB.cs:
using XYZ;
public class MainClass {
public static void Main() {
string s = "input";
s = s.Encrypt();
Console.WriteLine(s);
}
}
To create an Extension Method, the class must be static, but in general it has to follow these rules:
The class must be public and static
The method must be public and static
The type you want to create the extension method, in C#, must have the first parameter with the this keyword before the parameter
In your case, change the class to be static , for sample:
public static class Helpers
{
public static string Encrypt(this string plainText)
{
//... do encrypting
// return a string;
}
}
I also like to create the classes with name like Type and Extensions sufix, for sample: StringExtensions.cs, DateTimeExtensions.cs, etc.
Obs: Remember it is not a type method, it is just a static method, but you use as a method from a type.

Extension method must be defined in non-generic static class

Error at:
public partial class Form2 : Form
Probable cause:
public static IChromosome To<T>(this string text)
{
return (IChromosome)Convert.ChangeType(text, typeof(T));
}
Attempted (without static keyword):
public IChromosome To<T>(this string text)
{
return (IChromosome)Convert.ChangeType(text, typeof(T));
}
If you remove "this" from your parameters it should work.
public static IChromosome To<T>(this string text)
should be:
public static IChromosome To<T>(string text)
The class containing the extension must be static. Yours are in:
public partial class Form2 : Form
which is not a static class.
You need to create a class like so:
static class ExtensionHelpers
{
public static IChromosome To<T>(this string text)
{
return (IChromosome)Convert.ChangeType(text, typeof(T));
}
}
To contain the extension methods.
My issue was caused because I created a static method inside the partial class:
public partial class MainWindow : Window{
......
public static string TrimStart(this string target, string trimString)
{
string result = target;
while (result.StartsWith(trimString)){
result = result.Substring(trimString.Length);
}
return result;
}
}
When I removed the method, the error went away.
Because your containing class is not static, Extension method should be inside a static class. That class should be non nested as well. Extension Methods (C# Programming Guide)

How Can I inherit the string class?

I want to inherit to extend the C# string class to add methods like WordCount() and several many others but I keep getting this error:
Error 1 'WindowsFormsApplication2.myString': cannot derive from sealed
type 'string'
Is there any other way I can get past this ? I tried with string and String but it didn't work.
Another option could be to use an implicit operator.
Example:
class Foo {
readonly string _value;
public Foo(string value) {
this._value = value;
}
public static implicit operator string(Foo d) {
return d._value;
}
public static implicit operator Foo(string d) {
return new Foo(d);
}
}
The Foo class acts like a string.
class Example {
public void Test() {
Foo test = "test";
Do(test);
}
public void Do(string something) { }
}
System.String is sealed, so, no, you can't do that.
You can create extension methods. For instance,
public static class MyStringExtensions
{
public static int WordCount(this string inputString) { ... }
}
use:
string someString = "Two Words";
int numberOfWords = someString.WordCount();
If your intention behind inheriting from the string class is to simply create an alias to the string class, so your code is more self describing, then you can't inherit from string. Instead, use something like this:
using DictKey = System.String;
using DictValue= System.String;
using MetaData = System.String;
using SecurityString = System.String;
This means that your code is now more self describing, and the intention is clearer, e.g.:
Tuple<DictKey, DictValue, MetaData, SecurityString> moreDescriptive;
In my opinion, this code shows more intention compared to the same code, without aliases:
Tuple<string, string, string, string> lessDescriptive;
This method of aliasing for more self describing code is also applicable to dictionaries, hash sets, etc.
Of course, if your intention is to add functionality to the string class, then your best bet is to use extension methods.
You cannot derive from string, but you can add extensions like:
public static class StringExtensions
{
public static int WordCount(this string str)
{
}
}
What's wrong with a helper class? As your error message tells you, String is sealed, so your current approach will not work. Extension methods are your friend:
myString.WordCount();
static class StringEx
{
public static int WordCount(this string s)
{
//implementation.
}
}
You can't inherit a sealed class (that's the whole point of it) and the reason why it wouldn't work with both string and System.String is that the keyword string is simply an alias for System.String.
If you don't need to access the internals of the string class, what you can do is create an Extension Method, in your case :
//note that extension methods can only be declared in a static class
static public class StringExtension {
static public int WordCount(this string other){
//count the word here
return YOUR_WORD_COUNT;
}
}
You still won't have access to the private methods and properties of the string class but IMO it's better than writing :
StringHelper.WordCount(yourString);
That's also how LINQ works.
The string class is marked sealed because you are not supposed to inherit from it.
What you can do is implement those functions elsewhere. Either as plain static methods on some other class, or as extension methods, allowing them to look like string members.

Why is this extension method not working?

public static string ToTrimmedString(this DataRow row, string columnName)
{
return row[columnName].ToString().Trim();
}
Compiles fine but it doesn't show up in intellisense of the DataRow...
My guess is you haven't included the namespace.
Ensure this method is in a static class of its own, separate class from the consuming DataRow.
namespace MyProject.Extensions
{
public static class DataRowExtensions
{
//your extension methods
}
}
In your consumer, ensure you're:
using MyProject.Extensions
I had this same issue. My mistake wasn't that I missed the static class or static method but that the class my extensions were on was not public.
In addition to a missing using, following case with the same symptom may occur:
If you are inside a method of the class itself (or one if its implementors / inheritors), you need to make use of this.
File extension.cs:
namespace a
{
public static void AExt(this A a) {}
}
File user.cs
namespace a
{
class A {}
class B : A
{
this.AExt();
// AExt() will not work without this.
}
}
If you are using different namespaces try this code.
namespace Extensions
{
public static class StringExtensions
{
public static bool IsNumeric(this string inputString)
{
return decimal.TryParse(inputString, out decimal result);
}
}
}
namespace Business
{
// add here other namespaces
using Extensions;
public static class Tools
{
public static bool Check(string inputString)
{
return inputString.IsNumeric();
}
}
}
I had this same issue. My mistake is the argument type is not same: defined one is Session, revokded one is ISession.

How do you write a C# Extension Method for a Generically Typed Class

This should hopefully be a simple one.
I would like to add an extension method to the System.Web.Mvc.ViewPage< T > class.
How should this extension method look?
My first intuitive thought is something like this:
namespace System.Web.Mvc
{
public static class ViewPageExtensions
{
public static string GetDefaultPageTitle(this ViewPage<Type> v)
{
return "";
}
}
}
Solution
The general solution is this answer.
The specific solution to extending the System.Web.Mvc.ViewPage class is my answer below, which started from the general solution.
The difference is in the specific case you need both a generically typed method declaration AND a statement to enforce the generic type as a reference type.
I don't have VS installed on my current machine, but I think the syntax would be:
namespace System.Web.Mvc
{
public static class ViewPageExtensions
{
public static string GetDefaultPageTitle<T>(this ViewPage<T> v)
{
return "";
}
}
}
Thanks leddt.
Doing that yielded the error:
The type 'TModel' must be a reference
type in order to use it as parameter
'TModel' in the generic type or method
which pointed me to this page, which yielded this solution:
namespace System.Web.Mvc
{
public static class ViewPageExtensions
{
public static string GetDefaultPageTitle<T>(this ViewPage<T> v)
where T : class
{
return "";
}
}
}
It just needs the generic type specifier on the function:
namespace System.Web.Mvc
{
public static class ViewPageExtensions
{
public static string GetDefaultPageTitle<Type>(this ViewPage<Type> v)
{
return "";
}
}
}
Edit: Just missed it by seconds!
namespace System.Web.Mvc
{
public static class ViewPageExtensions
{
public static string GetDefaultPageTitle<T>(this ViewPage<T> view)
where T : class
{
return "";
}
}
}
You may also need/wish to add the "new()" qualifier to the generic type (i.e. "where T : class, new()" to enforce that T is both a reference type (class) and has a parameterless constructor.
Glenn Block has a good example of implementing a ForEach extension method to IEnumerable<T>.
From his blog post:
public static class IEnumerableUtils
{
public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
foreach(T item in collection)
action(item);
}
}
If you want the extension to only be available for the specified type
you simply just need to specify the actual type you will be handling
something like...
public static string GetDefaultPageTitle(this ViewPage<YourSpecificType> v)
{
...
}
Note intellisense will then only display the extension method when you declare your (in this case) ViewPage with the matching type.
Also, best not to use the System.Web.Mvc namespace, I know its convenient to not have to include your namespace in the usings section, but its far more maintainable if you create your own extensions namespace for your extension functions.
Here's an example for Razor views:
public static class WebViewPageExtensions
{
public static string GetFormActionUrl(this WebViewPage view)
{
return string.Format("/{0}/{1}/{2}", view.GetController(), view.GetAction(), view.GetId());
}
public static string GetController(this WebViewPage view)
{
return Get(view, "controller");
}
public static string GetAction(this WebViewPage view)
{
return Get(view, "action");
}
public static string GetId(this WebViewPage view)
{
return Get(view, "id");
}
private static string Get(WebViewPage view, string key)
{
return view.ViewContext.Controller.ValueProvider.GetValue(key).RawValue.ToString();
}
}
You really don't need to use the Generic version as the generic one extends the non-generic one so just put it in the non-generic base class and you're done :)

Categories

Resources