In this article, we’re going to tackle the popular question among many developers, and that’s “What’s the difference between string and String” and “When should I use string, and when should I use String” in my applications.

Both of these versions exist for a reason, so let’s see what they are and if they’re indeed that important.

This article is divided into the following sections:

Let’s dive in.

What Is String, and What Is String?

String or rather System.String is a class and it’s used to represent a sequence of UTF-16 code units or rather System.Char.Simply put it represents text. It’s a class like any other and it inherits from System.Object. It’s also a .NET (Framework or Core) type and its immutable by its nature which means it cannot be changed after it’s created. If you change it, you practically create and return another string upon modification of the existing string. That’s where StringBuilder comes in.

On the other hand, string is a C# reserved keyword and an alias for String. That means you can do something like this:

string foo = "hi";
String bar = "there!";

And this will be okay with the compiler, no problems whatsoever. It’s a nice feature and most of the time we don’t think too much about which one we use.

That brings us to the next point.

Are They the Same Thing?

But are they really the same thing though?

The answer is yes and no. What do we mean by that?

While they are the same and they compile the same way to the IL (Intermediate Language):

IL_0001: ldstr "hi"
IL_0006: stloc.0
IL_0007: ldstr "there!"
IL_000c: stloc.1

There are some differences to think about when using them. String can be anything because it’s not a reserved keyword. It can be used as a variable name for example. It’s not forbidden, but we’ll see what the cost of that can be. string on the other hand, cannot be used like that.

Other Aliases in C#

Beside string, there are several other aliases in C#:

  • object:  System.Object
  • bool:    System.Boolean
  • byte:    System.Byte
  • sbyte:   System.SByte
  • short:   System.Int16
  • ushort:  System.UInt16
  • int:     System.Int32
  • uint:    System.UInt32
  • long:    System.Int64
  • ulong:   System.UInt64
  • float:   System.Single
  • double:  System.Double
  • decimal: System.Decimal
  • char: System.Char

Mind you that not all of these are classes. Most of the types are structs and point to value types, with the exception of System.Objectand System.String.

What Are the Differences Between String and String in Practice?

To understand the differences even better, let’s go through some examples.

Example 1: variable names

var String = DateTime.Now; // Compiles perfectly
var string = DateTime.Now; // Does not compile

String can be used as a variable name, string cannot.

There is one exception to this rule and that’s by using a special character @ (verbatim identifier) as a prefix to indicate that the keyword can be used as an identifier:

var @string = DateTime.Now; // Compiles

As for the reason why you would do this ever, we have no idea. If you do, let us know in the comments section.

Example 2: nameof and typeof

Aliases, including string, can’t be used as a parameter for the nameof expression, because they are not types themselves.

var foo = nameof(string); // Syntax error
var bar = nameof(String); // Compiles normally

The typeof operator, on the other hand, is okay with either:
var foo = typeof(string); // Okay 
var bar = typeof(String); // Okay

In both cases, the result is the same and that’s System.String.

Example 3: underlying enum types

You might find this one while Google-ing, but it’s actually not true. It’s said that the underlying enum type must be declared as an alias:

public enum Foo : UInt32 {  } // Invalid supposedly
public enum Bar : uint {  } // Valid

This is not true, it both compiles, and the enum types are called as usual.

Example 4: context matters

Take a look at this example:

string foo = 20;  
String bar = 20;

What would you say the result of this code is? If you guessed syntax error in both cases, you were right.

But, that’s not the whole story.

If we add something like this:

using String = System.Int32;

It makes the syntax error on the second line disappear.

Why?

Because the compiler now treats the String type as an Int32 type. This just goes to show that string and String are not entirely the same.

Example 5: aliases as generic types

We can’t use a keyword as a generic type parameter, but we can name it String though:

public class GenericList<String> // Compiler agrees it's okay, but rolls its eyes
{
}

// or

public class GenericList<string> // No!
{
}

This is certainly not recommended, but it’s another example of how different these are.

Example 6: String as a class name

String can be a class name:

class MyClass
{
	protected class String
	{
	}

	void Example()
	{
		var foo = String.Format("Hello, today is {0}.", DateTime.Today.DayOfWeek);
		String bar = "Goodbye";
	}
}

There are some serious consequences of using it like that though. Both lines in the Example method are going to report a syntax error because now, String is just a class inside the MyClass. It’s not String anymore.

Example 7: String as an identifier

Same goes for using String as a variable name:

class MyClass<TElement>
{
	public IEnumerable<TElement> String { get; set; }

	void Example()
	{
		var foo = String.Format("Hello, today is {0}.", DateTime.Today.DayOfWeek);
	}
}

This inevitably results in a syntax error.

Enough examples? Let’s get to the important point.

Which One Should I Use?

There is a general consensus that string should be used when defining variable types, and that String should be used to call the String class methods and fields:

string foo = "Hi there";
var bar = String.Format("{0}, today is {0}.", foo, DateTime.Today.DayOfWeek);

We would go a bit further than that to say that if you work in a corporate environment, or in a team of developers, you should choose consistency over this style. Sometimes it’s more important to be consistent than to follow the unwritten rules that someone else has come up with.

But, Is It Just the Matter Style Though?

We’ve come to the most important part. Is this just a question of code style?

We’ve gone through some of the examples (Examples 4, 5, 6, 7) where we’ve seen that using String in certain scenarios can lead to potential problems, and there are some things that simply cannot be done with a keyword itself.

In terms of safety, it’s safer to use string over String, since compiler helps us avoid almost all problematic scenarios.

On the other hand, String is used in many valid scenarios like reflection, lexers, serialization, protocols… And for such libraries, string vs String might be an important issue.

We hope this clears it up a bit.

Conclusion

In this guide, we’ve reviewed the differences between String and string, and we’ve shown a few examples to demonstrate these differences.

If you have some interesting examples of string vs String yourself, we would like to hear from you in the comments section.