C# 7 out variables, tuples & other new features

C# 7 is available on new Visual Studio 2017 and comes with some new features. I wouldn’t call them ‘revolutionary’ features, but they add on the language very well and some of them can be very helpful. Personally, I have anticipated some features since C# 6 version.

TLDR; Sample code can be found here.

C# 7 comes with new features that I really like and I strongly believe they will be very useful in daily coding life, while others I think won’t help me anytime soon.
Look at C# Language Design on GitHub or  the proposals made from the community for the language, to get an idea of the new language features and the features to come.

Before I begin, I wish to share my experience with VS 2017, C# 7, .NET Standard/Core.
I used Visual Studio 2017 Community version to experiment with new syntax (I don’t have yet a license for Pro, sniff). I also wanted to experiment on code by writing some unit tests (this is my way to learn new stuff, I first write a unit test and then fiddle around with code, aiming to make it pass), so I used xUnit (which I am not a big fan of, but anyways). Both projects were .NET Standard 1.4 projects, but then I realized that this doesn’t work, as you can see on my SOpost. So, the answer was to make the test project a runnable application, I used .NET Core 1.1 but with no luck, so what I did in the end, was to create a new test project, targeting .NET Framework 4.6.2. Project with samples remained to .NET Standard.
Also, do not forget to use the System.Runtime Nuget package. Take a look on samples at Github (link is available above).

Out variables

Man, I love this. It is the first topic to discuss because I anticipated this for a long time. Personally, I really, really hated the old way, where you needed to declare a variable before calling the method with the output parameter. I was feeling funny everytime I was forced to code stuff like this:

int value;
 
int.TryParse("5", out value);
 
// Use value

I strongly believe that this is not elegant and I was really disappointed when they decided to not include this on C# 6 release.
But, here it is. Now you can declare the variable and the out parameter on the same line

int.TryParse("5", out int value);
 
// Use value

Yeah, I know, this isn’t exactly a revolution or an outstanding feature, but it is helpful and increases readability (of course, you need to get your eyes used to this new syntax, as you might lose a variable declaration while reading). Please note also that you can declare it as a var, instead of a specific type.

As it is expected, you can declare more than one output parameters (duh!) and use this new syntax. The cool thing with this though, is that you can decide which output parameter you wish and which you don’t. Cool stuff!
Bear with me, I know, the following example is a bit dull, but it demonstrates the use of discards (which can be declared with an underscore)

// Usage with two output parameters, fetching the first
CustomConverter.GetIntegerFromStringWithDiscards(out var x, out _);
 
// Usage with more than two output parameters, fetching the first
CustomConverter.GetIntegerFromStringWithDiscards(out var x, out _, out _);
 
// Usage with three output parameters, fetching the second
CustomConverter.GetIntegerFromStringWithDiscards(out _, out var y, out _);

As you can see, you omit the parameter you don’t wish to return using out _. How cool is the third example? You discard the first and the last and you get the middle one. Nice!

There is one gotcha though and this has to do with scoping. The scope rule is strict, having the variables accessible only in the scope body they are declared in.
That said, the following code will not work, you will get a compiler error, stating that the name ‘[name]’ does not belong to current context.

public static void GetIntegerFromStringWithDiscards(out int x, out int y)
{
    if (true) {
        int.TryParse("5", out var a);
        int.TryParse("6", out var b);
    }
 
    x = a;
    y = b;
}

but the following will work just fine

public static int GetIntTimesTenOrDefault(string number)
{
    if (int.TryParse(number, out int value)) {
        return value * 10;
    }
 
    // Value variable is visible to this scope, not only inside the if scope
    return value;
}

Tuples and deconstruction

The new syntax of tuples is awesome! I really like it and it kinda reminds me of JavaScript objects in some weird way, probably it’s just me, of course the syntax is not the same, but it reminds me that whenever I want to fetch a tuple value with that syntax.

Please note, in order to use the new tuples, you need to download a Nuget package, as it is not yet on core language code. So, that said, download the System.ValueTuple 4.3.0 (or higher)

Forget the old, rusty, rigid syntax for tuples, now you just declare them by type and you have them.
Look on the following example, the GetPerson method returns a Tuple with two strings and an integer.

public (string name, string surname, int age) GetPerson()
{
    return ("George", "Dyrrachitis", 28);
}

The syntax is pretty much simple. For declaration, you wrap in parenthesis the tuple items with their types and optionally names for them, if you want to make the signature more readable.
In order to create a tuple instance, you wrap your objects in parenthesis, of course matching the declaration, like in the example above, first define the two strings, then the integer value.

You consume it in a similar fashion. Of course, you can consume a simple tuple object and access each item individually like this:

var result = person.GetPerson();
// result.Item1
// result.Item2
// result.Item3

But this is not sexy, okay? What about this?

// Act
(string firstName, string lastName, int age) = person.GetPerson();
 
// Assert
Assert.Equal("George", firstName);
Assert.Equal("Dyrrachitis", lastName);
Assert.Equal(28, age);

That’s what I’m talking about! You can wrap your tuple elements in parenthesis, declare them and they are ready to be used like normal variables. Of course, you can declare them as varas well or even better, for shorthand syntax (see deconstruction below):

var (firstName, lastName, age) = person.GetPerson();

Declaring them all as vars.

Also, like out variables, tuples have discards as well, so you can omit elements you don’t wish  to use, just like at the following example.

[Fact]
public void GetOnlyFirstNameGeorgeFromTuple()
{
    // Arrange
    var person = new Person();
 
    // Act
    (var firstName, _, _) = person.GetPerson();
 
    // Assert
    Assert.Equal("George", firstName);
}
 
[Fact]
public void GetFirstNameAndAgeFromTuple()
{
    // Arrange
    var person = new Person();
 
    // Act
    (var firstName, _, var age) = person.GetPerson();
 
    // Assert
    Assert.Equal("George", firstName);
    Assert.Equal(28, age);
}

Finally, on tuples, there is another interesting feature, called deconstruction. We looked at that feature on the previous examples, with the sexy syntax.
But you can use it on classes as well, making them to behave like a tuple. You just need to declare a method called Deconstruct in your class, which can receive a number of output parameters, which will be deconstructed.

public class Person
{
    public Person(string firstName, string lastName, int age)
    {
        FirstName = firstName;
        LastName = lastName;
        Age = age;
    }
 
    public string FirstName { get; }
    public string LastName { get; }
    public int Age { get; }
 
    public void Deconstruct(out string firstName, out string lastName, out int age)
    {
        firstName = FirstName;
        lastName = LastName;
        age = Age;
    }
}

In the code above, I want to deconstruct a Person object to strings firstName,lastName and integer age. So, I use the Deconstruct method, declaring three output parameters, matching the description I gave earlier. I just give them the values from the public properties of the class, which were populated on instantiation.
Now, Person can be deconstructed like this:

[Fact]
public void DeconstructPersonObjectWithDeconstructor()
{
    // Arrange
    var person = new Person("George", "Dyrrachitis", 28);
 
    // Act
    var (firstName, lastName, age) = person;
 
    // Assert
    Assert.Equal("George", firstName);
    Assert.Equal("Dyrrachitis", lastName);
    Assert.Equal(28, age);
}

Groovy!

Pattern matching

Although pattern matching is a hot feature for the language, I won’t spend much time discussing that.

I would say that pattern matching is not that really useful to the language, it was a feature ‘nice to have’ mostly, by reading the patterns.md proposal, at least that is my take.
You can think of it as the Is operator in steroids. That operator is extended to test an expression against a pattern, and in this case we have various types of patterns.

We can  match an expression based on type or constant value or null and other discussed here.
This feature is very useful in some coding scenarios. Mostly, I like it because it gives me better syntax in an is-a situation or in testing a nullable type. Seriously, I like it only for that.
Check on the following example (of course the following can shorten significantly by using a ternary operator, but for the sake of the example I am more explicit)

public class TypesWithIsOperator
{
    public bool IsCustomReferenceType(object obj)
    {
        if (obj is CustomReferenceType t)
        {
            return t.True;
        }
 
        return false;
        // or for short: return obj is CustomReferenceType t ? t.True : false;
    }
 
    public bool IsNullableIntGreaterThanTen(int? value)
    {
        if (value is int v)
        {
            return v > 10;
        }
 
        return false;
        // or for short: return value is int v ? v > 10 : false;
    }
}
 
public class CustomReferenceType
{
    public bool True => true;
}

In IsCustomReferenceType method, I check if the object passed is of type CustomReferenceType and I create a new variable t of that type from the object (same as using the as operator and assigning the result to a new variable). Same goes for the IsNullableIntGreaterThanTen method, in which I check if the nullable integer value passed is not null, create a new variable v, assing the integer value there and return Boolean result based on its value.
In essence, I avoid doing this:

// With reference type
var t = obj as CustomReferenceType;
if(t != null) {
    return t.True;
}
return false;
 
// Or with value type
if(value.HasValue) {
    int v = value.Value;
    return v > 10;
}
return false;

Another coding scenario that pattern matching is useful and is demonstrated by almost everyone, is when using a switch-case statement. Now, you can match a case block by a pattern, which can be a type or a constant expression or null.
Be careful though, the patterns are not matched in an ordered fashion, as the compiler can match patterns out of order, as it is optimized to reuse the results of an already matched pattern in order to compute the result of matching of other patterns.
Also, note that the default case will execute last, regardless of the order you specify it on code.

public string MatchingMachineProduct(IMachine machine)
{
    switch (machine)
    {
        case PizzaMachine pizzaMachine:
            return pizzaMachine.Make();
        case FishAndChipsMachine fishAndChipsMachine:
            return fishAndChipsMachine.Make();
        default:
            return null;
        case null:
            throw new ArgumentNullException(nameof(machine));
    }
}

Other features

Local functions

Other features that I like are the local functions. I think this is a good addition and improves readability.
When reading on code, as a human being, I read from top to bottom and jumping to references while reading, meaning I will jump to the next function declared. I prefer to write a private function immediately after its call, so a reader can jump to it directly, without much effort searching in the class.
With local functions, you literally have the chance to write it just after your call in the caller’s body. All the caller’s scoped variables are available within the local function, which helps you to define more readable signatures, with less parameters (the more the parameters a method has, the dirtier it is).
Of course, this is one advantage that it gives you, the other is scoping, the only one that has access to this method is the caller and only that. This can help you create more meaningful inner functions, closer to the caller’s context.

public class Bubblesort
{
    private readonly int[] _array;
 
    public Bubblesort(int[] array) =>  _array = array;
 
    public void Sort()
    {
        for (var i = _array.Length - 1; i > 1; i--)
            for (var j = 0; j < i; j++) if (_array[j] > _array[j + 1])
                    Swap(j, j + 1);
 
        void Swap(int i, int j)
        {
            var temp = _array[i];
            _array[i] = _array[j];
            _array[j] = temp;
        }
    }
}

Be careful though, not to overdo it, as this can lead to some insanely huge looking parent methods, which is the worst thing you can do with your code. As a rule of thumb, use local functions only when you know they will be short, else use other private methods and try to separate concerns, do not make methods more 10-20 lines long.

Always remember:

  • 1-10 lines is perfect
  • 10-20, you need a short check on code
  • 20-30, it’s getting out of hand
  • 50-60+, Houston, we have a problem

If your method does not fit your screen, then you are in some deep trouble. And don’t cheat with pivot screens.

Expression bodied members

Finally, this is another great feature. I loved expression bodied members in the previous release, my single line methods looked so good with that syntax.
With the new syntax, constructors, destructors, even getters and setters can have expression bodies.
Look on the previous example, the constructor has an expression body.

Throw expressions

You can throw an exception when using the ternary conditional operator (?:), the null coalescing operator (??) or as the body of an expression-bodied lamda or method.
Take a look at the following examples:

// Using the ternary conditional operator
return condition ? "Yes, it's true" : throw new Exception("Oops");
 
// Using the null coalescing operator
return value ?? throw new Exception("Oops");
 
// Expression-bodied method
public void Throws() => new Exception("Oops");

Summary

Cool new features, improving your experience with the language.
I haven’t been through many other features, maybe the most notorious of them, the pattern matching. This is on purpose. As I said in the beginning, my intention was to go through stuff that I find useful in my daily routine, and for the moment, I do not find pattern matching that useful for me. Probably I need to dig deeper and see the advantages, but for the moment I do not use it.

What new features do you use? Do they come in handy for you?

C# 7 out variables, tuples & other new features的更多相关文章

  1. Machine Learning : Pre-processing features

    from:http://analyticsbot.ml/2016/10/machine-learning-pre-processing-features/ Machine Learning : Pre ...

  2. Halcon相关

      1.Halcon的自我描述 Program Logic Ø Each program consists of a sequence of HALCON operators Ø The progra ...

  3. .NET和C#的版本历史

    维基百科页面:https://en.wikipedia.org/wiki/.NET_Framework_version_history Versionnumber CLRversion Release ...

  4. modern-cpp-features

    C++17/14/11 Overview Many of these descriptions and examples come from various resources (see Acknow ...

  5. SSAS 通过 ETL 自动建立分区

    一.动态分区的好处就不说了,随着时间的推移,不可能一个度量值组都放在一个分区中,处理速度非常慢,如何动态添加分区,如何动态处理分区,成为了很多新手BI工程师一个头痛的问题,废话不多说,分享一下我的经验 ...

  6. SSAS动态添加分区(一)

    一.动态分区的好处就不说了,随着时间的推移,不可能一个度量值组都放在一个分区中,处理速度非常慢,如何动态添加分区,如何动态处理分区,成为了很多新手BI工程师一个头痛的问题,废话不多说,分享一下我的经验 ...

  7. SSAS动态添加分区 (转载)

    一.动态分区的好处就不说了,随着时间的推移,不可能一个度量值组都放在一个分区中,处理速度非常慢,如何动态添加分区,如何动态处理分区,成为了很多新手BI工程师一个头痛的问题,废话不多说,分享一下我的经验 ...

  8. Automake

    Automake是用来根据Makefile.am生成Makefile.in的工具 标准Makefile目标 'make all' Build programs, libraries, document ...

  9. 时间序列预测——深度好文,ARIMA是最难用的(数据预处理过程不适合工业应用),线性回归模型简单适用,预测趋势很不错,xgboost的话,不太适合趋势预测,如果数据平稳也可以使用。

    补充:https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-15-276 如果用arima的话,还不如使用随机森 ...

随机推荐

  1. ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue, RingBuffer

    1. ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue ArrayBlockingQueue, LinkedBlocking ...

  2. 奇怪吸引子---Dadras

    奇怪吸引子是混沌学的重要组成理论,用于演化过程的终极状态,具有如下特征:终极性.稳定性.吸引性.吸引子是一个数学概念,描写运动的收敛类型.它是指这样的一个集合,当时间趋于无穷大时,在任何一个有界集上出 ...

  3. [leetcode]Pascal's Triangle @ Python

    原题地址:https://oj.leetcode.com/problems/pascals-triangle/ 题意: Given numRows, generate the first numRow ...

  4. 鼠标悬浮在img上让图片变大

    样式: <style type="text/css">        img:hover{ transform:scale(1.02,1.02)}</style& ...

  5. AS 阿里巴巴Java开发规约 CheckStyle-IDEA

    Alibaba Java Coding Guidelines 简介 github地址:https://github.com/alibaba/p3c  官方文档    阿里巴巴Java开发手册(纪念版) ...

  6. MFC中位图的显示

    分析: 首先,我们要明确一点,窗口的绘制包括两个步骤,首先:擦除窗口背景,然后再对窗口重新进行绘制:当擦除窗口背景时,程序会发生一个WM_ERASEBKGND消息,因此可以在此响应函数中完成位图的显示 ...

  7. mysql的sql分页函数limit使用 (转)

    http://www.cnblogs.com/beijingstruggle/p/5631603.html mysql的sql分页函数limit使用 My sql数据库最简单,是利用mysql的LIM ...

  8. VS2013开发asmx接口返回一个自定义XML

    1:利用XmlDocument生成一个xml文档返回,代码如下 using System;using System.Collections.Generic;using System.Linq;usin ...

  9. 国内A股16家上市银行的財务数据与股价的因子分析报告(1)(工具:R)

    分析人:BUPT_LX 研究目的 用某些算法对2014年12月份的16家国内A股上市的商业银行当中11项財务数据(资产总计.负债合计.股本.营业收入.流通股A.少数股东权益.净利润.经营活动的现金流量 ...

  10. 给ajax表单提交数据前面加上实体名称

    有时候我们后台做了一个引用类型例如: 下面的实体以C#为例 public class Order{ public string orderId{get;set;} public OrderItem o ...