29

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.

Jon Egerton
  • 40,401
  • 11
  • 97
  • 129
Nasreddine
  • 36,610
  • 17
  • 75
  • 94

7 Answers7

106

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) { }
}
Adam Calvet Bohl
  • 1,009
  • 14
  • 29
René
  • 1,211
  • 2
  • 10
  • 3
  • An excellent option indeed! Personally, I think the wrapper is more useful since it allows you to define your own type rather than simply add new functions. I am using this to implement a `LogicalString` which compares using [natural sort](http://blog.codinghorror.com/sorting-for-humans-natural-sort-order/) (like Windows Explorer). – Nicholas Miller Aug 14 '15 at 15:40
  • 7
    The "return d.ToString()" requires the ToString() to be implemented or classname is returned instead. Think it should return d._value. A bit off topic but interesting is if the example is used to inspire storing multiple type objects in a class and more operators are implemented to handle the exchange of the actual datatypes to and from the outer world. A bit attention to "d" referring to the class itself and d._value to referring to the stored value. If ToString() is not implemented we get the default implementation returning the class name. – tofo Sep 30 '16 at 10:31
  • 2
    Brilliant solution. You can then add validation for construction, some `==`, `!=` operators, `Equals` and `GetHashCode` methods and you have a sweet encapsulated value object. I just used the above solution, along with the additional members mentioned above to great effect. – Dib Feb 07 '17 at 15:42
  • 1
    I fixed it, here is the change return d.ToString(); should be return d._value; or you get a string of the object description like in GetType() – Omzig Nov 30 '17 at 16:03
  • I fixed it but some goober rejected the fix. There is no way for me to appeal the rejection that Jon Adams did in haste. – Omzig Nov 30 '17 at 16:12
  • 2
    @Omzig, true, it should be `return d._value;`. – Adam Calvet Bohl Aug 03 '18 at 08:11
  • 2
    I love this solution. Using this method I can define my own "string classes" that acts as a string in everyday use, but at the same are type safe so that the compiler will prevent me from assigning a Foo1 variable to a Foo2 variable even though they are both strings. – pberggreen Nov 22 '18 at 08:16
  • In addition, you'd might want to implement explicit operators, equality and comparison members. – dbardakov Sep 04 '20 at 09:59
  • @pberggreen I wanted to use this solution exactly for this purpose (sort of mimic enum of strings), but the `public static implicit operator Foo(string d)` enables assigning any new string to my `Foo` value. Unlike C++, .NET requires overloaded operators to be public and static. Hence I had to set it as explicit to require the user think twice before using it :) – Sold Out Jan 20 '21 at 15:26
  • Even if this is a rather old thread I'd like to share my opinion. I'd rather declare the "new" string type as a struct, since that is the behaviour you would expect from a string as well. When you pass your string "class" into a function it will be copied by reference, you have to be careful not to modify properties inside that reference or you will be altering the original object. If you declare it as a struct or even a record you wont have to deal with these kind of problems. – Leon Bohmann Jul 23 '22 at 23:55
  • It's a nice solution! but the following doesn't seem to work `Foo result = new Foo("test"); // result is "test" DoFoo(result); // result is still "test" void DoFoo(Foo foo) { foo = "test_foo"; }` – bartburkhardt Oct 06 '22 at 23:06
  • nice trick! And you'll have to mimic string's methods in `Foo` as well (at least the ones which are used in the code), so you could call `foo.EndsWith("test")` and alike – AntonK Mar 24 '23 at 14:05
45

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();
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
John Saunders
  • 160,644
  • 26
  • 247
  • 397
  • 6
    If you don't know what [extension methods](http://msdn.microsoft.com/en-us/library/bb383977.aspx) are (as I didn't), that page is a good resource. – Brigand Dec 05 '11 at 17:07
18

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.

Community
  • 1
  • 1
Contango
  • 76,540
  • 58
  • 260
  • 305
  • 8
    I like your answer, but unfortunatly it's not really for this question :P – Marcin Konrad Ceglarek Mar 29 '16 at 18:12
  • 2
    With C# tuple types and tuple literals features you can express this intention in a more precise form: `(string DictKey, string DictValue, string MetaData) betterTuple;` and use it like this `betterTuple.DictKey = "key";` – dbardakov Mar 20 '19 at 17:04
5

You cannot derive from string, but you can add extensions like:

public static class StringExtensions
{
    public static int WordCount(this string str)
    {
    }
}
Daniel
  • 30,896
  • 18
  • 85
  • 139
1

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.

Nasreddine
  • 36,610
  • 17
  • 75
  • 94
1

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.
    }
}
spender
  • 117,338
  • 33
  • 229
  • 351
-6

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.

Peter Morris
  • 20,174
  • 9
  • 81
  • 146
jalf
  • 243,077
  • 51
  • 345
  • 550