Skip to content
131 changes: 131 additions & 0 deletions docs/csharp/versioning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
---
title: C# Versioning | C# Guide
description: Understand how versioning works in C# and .NET
keywords: .NET, .NET Core, C#
author: tsolarin
manager: wpickett
ms.date: 01/08/2017
ms.topic: article
ms.prod: visual-studio-dev-14
ms.technology: devlang-csharp
ms.devlang: csharp
ms.assetid: aa8732d7-5cd0-46e1-994a-78017f20d861
---

# Versioning in C# #

In this tutorial you'll learn what versioning means in .NET. You'll also learn the factors to consider when versioning your library as well as upgrading
to a new version of the a library.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a brief introduction here to tell readers what they will learn by reading this article. One or two paragraphs is all it should take.

## Authoring Libraries

As a developer who has created .NET libraries for public use, you've most likely been in situations where you have
to roll out new updates. How you go about this process matters a lot as you need to ensure that there's a seamless transition
of existing code to the new version of your library. Here are several things to consider when creating a new release:

### Semantic Versioning

[Semantic versioning](http://semver.org/) (SemVer for short) is a naming convention applied to versions of your library to signify specific milestone events.
Ideally, the version information you give your library should help developers determine the compatibility
with their projects that make use of older versions of that same library.

The most basic approach to SemVer is the 3 component format `MAJOR.MINOR.PATCH`, where:

* `MAJOR` is incremented when you make incompatible API changes
* `MINOR` is incremented when you add functionality in a backwards-compatible manner
* `PATCH` is incremented when you make backwards-compatible bug fixes

There are also ways to specify other scenarios like pre-release versions etc. when applying version information to your .NET library.

### Backwards Compatibility

As you release new versions of your library, backwards compatibility with previous versions will most likely be one of your major concerns.
A new version of your library is source compatible with a previous version if code that depends on the previous version can, when recompiled, work with the new version.
A new version of your library is binary compatible if an application that depended on the old version can, without recompilation, work with the new version.

Here are some things to consider when trying to maintain backwards compatibility with older versions of your library:

* Virtual methods: When you make a virtual method non-virtual in your new version it means that projects that override that method
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be more prescriptive here. I think it is safe to say that is such a breaking change that this should be strongly discouraged.

will have to be updated. This is a huge breaking change and is strongly discouraged.
* Method signatures: When updating a method behaviour requires you to change its signature as well, you should instead create an overload so that code calling into that method will still work.
You can always manipulate the old method signature to call into the new method signature so that implementation remains consistent.
* [Obsolete attribute](programming-guide/concepts/attributes/common-attributes.md#Obsolete): You can use this attribute in your code to specify classes or class members that are deprecated and likely to be removed in future versions.
This ensures developers utilizing your library are better prepared for breaking changes.
* Optional Method Arguments: When you make previously optional method arguments compulsory or change their default value then all code that does not supply those arguments will need to be updated.
> [!NOTE]
> Making compulsory arguments optional should have very little effect especially if it doesn't change the method's behaviour.

The easier you make it for your users to upgrade to the new version of your library, the more likely that they will upgrade sooner.

### Application Configuration File

As a .NET developer there's a very high chance you've encountered [the `app.config` file](https://msdn.microsoft.com/en-us/library/1fk1t1t0(v=vs.110).aspx) present in most project types.
This simple configuration file can go a long way into improving the rollout of new updates. You should generally design your libraries in such
a way that information that is likely to change regularly is stored in the `app.config` file, this way when such information is updated
the config file of older versions just needs to be replaced with the new one without the need for recompilation of the library.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a closing before you go on. Consider this point: the easier you make it for your users to upgrade to the new version of your library, the more likely that they will upgrade sooner.

## Consuming Libraries

As a developer that consumes .NET libraries built by other developers you're most likely aware that a new version of a library might not be fully compatible with your project
and you might often find yourself having to update your code to work with those changes.

Lucky for you C# and the .NET ecosystem comes with features and techniques that allow us to easily update our app to work with new versions of libraries that might introduce breaking changes.

### Assembly Binding Redirection

You can use the `app.config` file to update the version of a library your app uses. By adding what is called a [*binding redirect*](https://msdn.microsoft.com/en-us/library/7wd6ex19(v=vs.110).aspx) your
can use the new library version without having to recompile your app. The following example shows how you would update
your app's `app.config` file to use the `1.0.1` patch version of `ReferencedLibrary` instead of the `1.0.0` version it was originally compiled with.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would reference the section above where you talk about how to ensure binary compatibility.


```xml
<dependentAssembly>
<assemblyIdentity name="ReferencedLibrary" publicKeyToken="32ab4ba45e0a69a1" culture="en-us" />
<bindingRedirect oldVersion="1.0.0" newVersion="1.0.1" />
</dependentAssembly>
```

> [!NOTE]
> This approach will only work if the new version of `ReferencedLibrary` is binary compatible with your app.
> See the [Backwards Compatibility](#backwards-compatibility) section above for changes to look out for when determining compatibility.

### new

You use the `new` modifier to hide inherited members of a base class. This is one way derived classes can respond to updates in base classes.

Take the following example:

[!code-csharp[Sample usage of the 'new' modifier](../../samples/csharp/versioning/new/Program.cs#sample)]

**Output**

```
A base method
A derived method
```

From the example above you can see how `DerivedClass` hides the `MyMethod` method present in `BaseClass`.
This means that when a base class in the new version of a library adds a member that already exists in your derived class, you can
simply use the `new` modifier on your derived class member to hide the base class member.

When no `new` modifier is specified, a derived class will by default hide conflicting members in a base class,
although a compiler warning will be generated the code will still compile. This means that simply adding new members to an existing class
makes that new version of your library both source and binary compatible with code that depends on it.

### override

The `override` modifier means a derived implementation extends the implementation of a base class member rather than
hides it. The base class member needs to have the `virtual` modifier applied to it.

[!code-csharp[Sample usage of the 'override' modifier](../../samples/csharp/versioning/override/Program.cs#sample)]

**Output**

```
Base Method One: Method One
Derived Method One: Derived Method One
```

The `override` modifier is evaluated at compile time and the compiler will throw an error if it doesn't find a virtual member to override.

Your knowledge of the discussed techniques as well as your understanding of what situations to use them will go a long way to boost the ease
of transition between versions of a library.
3 changes: 2 additions & 1 deletion docs/toc.md
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,8 @@
#### [Summary](csharp/expression-trees-summary.md)
### [Native interoperability](csharp/programming-guide/interop/interoperability.md)
### [🔧 Reflection & code generation](csharp/reflection.md)
### [Documenting your code](csharp/codedoc.md)
### [Documenting your code](csharp/codedoc.md)
### [Versioning](csharp/versioning.md)
## [🔧 Using the .NET Compiler Platform](csharp/roslyn/index.md)

## [C# Programming Guide](csharp/programming-guide/index.md)
Expand Down
31 changes: 31 additions & 0 deletions samples/csharp/versioning/new/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;

class Program
{
#region sample
public class BaseClass
{
public void MyMethod()
{
Console.WriteLine("A base method");
}
}

public class DerivedClass : BaseClass
{
public new void MyMethod()
{
Console.WriteLine("A derived method");
}
}

public static void Main()
{
BaseClass b = new BaseClass();
DerivedClass d = new DerivedClass();

b.MyMethod();
d.MyMethod();
}
#endregion
}
25 changes: 25 additions & 0 deletions samples/csharp/versioning/new/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
C# Versioning Sample
================

This sample is created during the [Versioning](https://docs.microsoft.com/dotnet/articles/csharp/versioning)
for learning C# features. Please see that topic for detailed steps on the code
for this sample.

Key Features
------------

This sample contains code demonstrating the use of
the `new` modifier when versioning .NET libraries

Build and Run
-------------

To build and run the sample, type the following three commands:

`dotnet restore`
`dotnet build`
`dotnet run`

`dotnet restore` installs all the dependencies for this sample into the current directory.
`dotnet build` creates the output assembly (or assemblies).
`dotnet run` runs the output assembly.
19 changes: 19 additions & 0 deletions samples/csharp/versioning/new/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
},
"dependencies": {},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
},
"imports": "dnxcore50"
}
}
}
31 changes: 31 additions & 0 deletions samples/csharp/versioning/override/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;

class Program
{
#region sample
public class MyBaseClass
{
public virtual string MethodOne()
{
return "Method One";
}
}

public class MyDerivedClass : MyBaseClass
{
public override string MethodOne()
{
return "Derived Method One";
}
}

public static void Main()
{
MyBaseClass b = new MyBaseClass();
MyDerivedClass d = new MyDerivedClass();

Console.WriteLine("Base Method One: {0}", b.MethodOne());
Console.WriteLine("Derived Method One: {0}", d.MethodOne());
}
#endregion
}
25 changes: 25 additions & 0 deletions samples/csharp/versioning/override/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
C# Versioning Sample
================

This sample is created during the [Versioning](https://docs.microsoft.com/dotnet/articles/csharp/versioning)
for learning C# features. Please see that topic for detailed steps on the code
for this sample.

Key Features
------------

This sample contains code demonstrating the use of
the `override` modifier when versioning .NET libraries

Build and Run
-------------

To build and run the sample, type the following three commands:

`dotnet restore`
`dotnet build`
`dotnet run`

`dotnet restore` installs all the dependencies for this sample into the current directory.
`dotnet build` creates the output assembly (or assemblies).
`dotnet run` runs the output assembly.
19 changes: 19 additions & 0 deletions samples/csharp/versioning/override/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
},
"dependencies": {},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
},
"imports": "dnxcore50"
}
}
}