C# is a powerful and popular programming language, with a rich set of features that allow developers to build a wide range of applications. However, like any language, C# has a number of lesser-known features that can be useful in certain situations. In this article, we'll explore some of these hidden gems and see how they can be used in practice.
Volatile
The volatile keyword is used to indicate that a field can be modified by multiple threads simultaneously. When a field is marked as volatile, the compiler and runtime will take extra steps to ensure that its value is always up-to-date, even in the presence of concurrent access.
Here's an example of how to use volatile:
public class Counter
{
private volatile int _count;
public int Count
{
get { return _count; }
set { _count = value; }
}
}
extern alias
The extern alias keyword is used to specify an alias for a namespace when using a type from another assembly. This can be useful when you have multiple assemblies that contain types with the same names, and you want to disambiguate them.
Here's an example of how to use extern alias:
extern alias MyLibrary;
using System;
using MyLibrary::MyNamespace;
public class Program
{
static void Main()
{
Console.WriteLine(typeof(MyNamespace.MyType));
}
}
__arglist
The __arglist keyword is used to specify a variable number of arguments in a method declaration. It allows you to pass a variable number of arguments to a method, without using the params keyword.
Here's an example of how to use __arglist:
public static void PrintNumbers(__arglist)
{
var args = new ArgIterator(__arglist);
while (args.GetRemainingCount() > 0)
{
Console.WriteLine(__refvalue(args.GetNextArg(), int));
}
}
__makeref and __reftype
The __makeref and __reftype keywords are used to work with managed object references in an unsafe context. The __makeref keyword creates a reference to an object, while the __reftype keyword returns the type of an object that is being referenced.
Here's an example of how to use __makeref and __reftype:
unsafe void ModifyString(string s)
{
TypedReference tr = __makeref(s);
if (__reftype(tr) == typeof(string))
{
// Modify the string through the typed reference
}
}
as and is keywords
The as and is keywords are used to perform type conversions and type checks, respectively. The as operator performs a type conversion, and returns null if the conversion fails. The is operator returns a boolean indicating whether an object is of a specific type.
Here's an example of how to use as and is:
object obj = "hello";
string s = obj as string;
if (s != null)
{
Console.WriteLine(s.Length); // 5
}
if (obj is string)
{
Console.WriteLine(((string)obj).Length); // 5
}
Coalesce Nulls
The coalesce nulls operator, represented by the ??= operator, is used to assign a value to a nullable type only if it is currently null. This can be useful when you want to set a default value for a nullable type, without overwriting any existing values.
Here's an example of how to use the coalesce nulls operator:
int? x = null;
x ??= 42; // x is now 42
x ??= 24; // x is still 42
where T: new
The where T: new constraint is used to specify that a type parameter must have a public parameterless constructor. This can be useful when you want to ensure that a type can be instantiated using the default constructor.
Here's an example of how to use the where T: new constraint:
public class MyClass<T> where T: new()
{
public T CreateInstance()
{
return new T();
}
}
global::
The global:: prefix is used to specify that a type or member refers to the global namespace, rather than a namespace with the same name in the current context. This can be useful when you want to disambiguate types or members that have the same name as a namespace.
Here's an example of how to use global::
namespace MyNamespace
{
class MyClass
{
global::System.Int32 x; // refers to the Int32 type in the global namespace
}
}
Conclusion
In this article, we explored some of the lesser-known features of C#, including volatile, extern alias, __arglist, __makeref and __reftype, as and is, coalesce nulls, where T: new, and global::. While these features may not be used frequently, they can be useful in certain situations and are worth knowing about. Understanding these features can help you write more efficient and effective code in C#, and can also deepen your understanding of the language as a whole.
Top comments (1)
It's a funny thing,
volatile
. Back 14 or so years ago when I was doing C++ heavily, I learned thatvolatile
in non-Microsoft compilers was simply meant as a hint for the compiler to avoid code optimization around variables that may not seem to have assignments. It was used for variables that were set from DLL's or similar.The funny thing is: Out of all C++ compilers, Microsoft's compiler was the only one to also add synchronization around the variable, making it thread-safe. No other C++ compiler would do this, only these guys'.
I suppose they carried their decision in C++ all the way into C#.
BTW, it would have been nice to start with
unsafe
andunchecked
before__makeref
and__reftype
. Now people that don't know these ones will remain scratching their heads about the whole thing, hehe. 😄