New C# 7 features in action: Deconstruction in C# 7 – deconstructing declaration, deconstructing assignment, deconstructor method and discards in deconstruction.
Deconstruction in C# 7
Deconstruction feature can be used to consume tuples. Also, deconstruction feature can be used for user-defined types in .NET but for that you need to provide Deconstruct method.
public void Deconstruct(out T1 x1, ..., out Tn xn) { ... }
You can provide multiple overloads of Deconstruct method.
Deconstruction for Tuples
Note: HasValue function used in the below examples returns(bool isValid, int errorCode, string errorMessage)
Tuple type.
private static (bool isValid, int errorCode, string errorMessage) HasValue(string inputString) // tuple return type { //Some code }
A. deconstructing declaration
By deconstructing a tuple, you can assign its elements individually to fresh variables as shown below:
(bool isValid, int errorCode, string errorMessage) = HasValue(inputString);
B. deconstructing assignment
By deconstructing a tuple, you can also assign its elements individually to existing variables as shown below:
public static bool IsValidInputStringWithLogging(string inputString, out int errorCode, out string errorMessage) { bool isValid; (isValid, errorCode, errorMessage) = HasValue(inputString); // deconstructing assignment // Some code }
C. discards in deconstruction
C# 7 allows discards in deconstruction, you can ignore the elements of tuple that you don’t require.
Here, we don’t require “errorCode” and “errorMessage”, so we can discard them as shown below:
(bool isValid, _, _) = CSharp7Sample.HasValue(inputString); // deconstructing declaration with discard. Here, we don't require "errorCode" and "errorMessage"
Deconstruction for User-Defined Types
Note: HasValue function used in the below examples returns OperationResult
.
private static OperationResult HasValue(string inputString) { //Some code }
A. deconstructor method
For User-Defined Types, you need to provide Deconstruct method to use deconstruction feature.
public class OperationResult { public bool Status { get; set; } public int ErrorCode { get; set; } public string ErrorMessage { get; set; } public void Deconstruct(out bool status, out int errorCode, out string errorMessage) { status = this.Status; errorCode = this.ErrorCode; errorMessage = this.ErrorMessage; } }
B. deconstructor method overload
You can also provide multiple overloaded Deconstruct methods.
public class OperationResult { public bool Status { get; set; } public int ErrorCode { get; set; } public string ErrorMessage { get; set; } public void Deconstruct(out bool status, out string logErrorMessage) { status = this.Status; logErrorMessage = $"{nameof(this.ErrorCode)}: {this.ErrorCode}, {nameof(this.ErrorMessage)}: {this.ErrorMessage}"; } public void Deconstruct(out bool status, out int errorCode, out string errorMessage) { status = this.Status; errorCode = this.ErrorCode; errorMessage = this.ErrorMessage; } }
C. deconstructing declaration
The below sample calls Deconstruct(out isValid, out errorCode, out errorMessage);
(bool isValid, int errorCode, string errorMessage) = HasValue(inputString); // deconstructing declaration
The below sample calls Deconstruct(out isValid, out logErrorMessage);
(bool isValid, string logErrorMessage) = CSharp7Sample.HasValue(inputString); // deconstructing declaration
D. deconstructing assignment
public static bool IsValidInputStringWithLogging(string inputString, out int errorCode, out string errorMessage) { bool isValid; (isValid, errorCode, errorMessage) = HasValue(inputString); // deconstructing assignment // Some code }
E. discards in deconstruction
C# 7 allows discards in deconstruction, you can ignore items returned by a Deconstruct method that you don’t require.
(bool isValid, _, _) = HasValue(inputString); // deconstructing declaration with discard. Here, we don't require "errorCode" and "errorMessage"
Full working sample code to demonstrate the C# 7’s Deconstruction feature-deconstructing declaration, deconstructing assignment, deconstructor method and discards in deconstruction.
Full working sample code to explain the use of Deconstruction for Tuples
CSharp7Sample class contains example to explain: deconstructing declaration, deconstructing assignment and discards in deconstruction.
/// <summary> /// CSharp7Sample. /// </summary> public partial class CSharp7Sample { /// <summary> /// Checks Input String is valid (with logging). /// </summary> /// <param name="inputString">Input string.</param> /// <returns>true or false.</returns> public static bool IsValidInputStringWithLogging(string inputString) { (bool isValid, int errorCode, string errorMessage) = CSharp7Sample.HasValue(inputString); // deconstructing declaration if (isValid == false) { string logMessage = $"{nameof(inputString)}: {inputString}, {nameof(errorCode)}: {errorCode}, {nameof(errorMessage)}: {errorMessage}"; Console.Write(logMessage); } return isValid; } /// <summary> /// Checks Input String is valid (with logging). /// </summary> /// <param name="inputString">Input string.</param> /// <returns>true or false.</returns> public static bool IsValidInputStringWithLogging(string inputString, out int errorCode, out string errorMessage) { bool isValid; (isValid, errorCode, errorMessage) = CSharp7Sample.HasValue(inputString); // deconstructing assignment if (isValid == false) { string logMessage = $"{nameof(inputString)}: {inputString}, {nameof(errorCode)}: {errorCode}, {nameof(errorMessage)}: {errorMessage}"; Console.Write(logMessage); } return isValid; } /// <summary> /// Checks Input String is valid (without logging). /// </summary> /// <param name="inputString">Input string.</param> /// <returns>true or false.</returns> public static bool IsValidInputStringWithoutLogging(string inputString) { (bool isValid, _, _) = CSharp7Sample.HasValue(inputString); // deconstructing declaration with discard. Here, we don't require "errorCode" and "errorMessage" return isValid; } /// <summary> /// Input string has value or not. /// </summary> /// <param name="inputString">Input string.</param> /// <returns>Tuple.</returns> private static (bool isValid, int errorCode, string errorMessage) HasValue(string inputString) // tuple return type - (bool isValid, int errorCode, string errorMessage) { int code = 0; string message = string.Empty; if (inputString == null) { code = 1; message = "Input string is null"; } else if (inputString.Equals(string.Empty)) { code = 2; message = "Input string is empty"; } else if (inputString.Trim().Equals(string.Empty)) { code = 3; message = "Input string only whitespaces"; } bool success = string.IsNullOrEmpty(message); return (isValid: success, errorCode: code, errorMessage: message); // tuple literal - (isValid: success, errorCode: code, errorMessage: message) } }
Full working sample code to explain the use of Deconstruction for User-Defined Types
OperationResult class with overloaded Deconstruct methods.
/// <summary> /// OperationResult. /// </summary> public class OperationResult { /// <summary> /// Gets or sets a value indicating whether status is true. /// </summary> public bool Status { get; set; } /// <summary> /// Gets or sets the error code. /// </summary> public int ErrorCode { get; set; } /// <summary> /// Gets or sets the error message. /// </summary> public string ErrorMessage { get; set; } /// <summary> /// Gets or sets the Error Message for logging. /// </summary> public string LogErrorMessage { get; set; } /// <summary> /// Deconstruct. /// </summary> /// <param name="status">Status.</param> /// <param name="logErrorMessage">Error Message for logging.</param> public void Deconstruct(out bool status, out string logErrorMessage) { status = this.Status; logErrorMessage = $"{nameof(this.ErrorCode)}: {this.ErrorCode}, {nameof(this.ErrorMessage)}: {this.ErrorMessage}"; } /// <summary> /// Deconstruct. /// </summary> /// <param name="status">Status.</param> /// <param name="errorCode">Error Code.</param> /// <param name="errorMessage">Error Message.</param> public void Deconstruct(out bool status, out int errorCode, out string errorMessage) { status = this.Status; errorCode = this.ErrorCode; errorMessage = this.ErrorMessage; } }
CSharp7Sample class contains example to explain: deconstructing declaration, deconstructing assignment and discards in deconstruction.
/// <summary> /// CSharp7Sample. /// </summary> public partial class CSharp7Sample { /// <summary> /// Checks Input String is valid (with logging). /// </summary> /// <param name="inputString">Input string.</param> /// <returns>true or false.</returns> public static bool IsValidInputStringWithLogging(string inputString) { (bool isValid, int errorCode, string errorMessage) = CSharp7Sample.HasValue(inputString); // deconstructing declaration - calls Deconstruct(out isValid, out errorCode, out errorMessage); if (isValid == false) { string logMessage = $"{nameof(inputString)}: {inputString}, {nameof(errorCode)}: {errorCode}, {nameof(errorMessage)}: {errorMessage}"; Console.Write(logMessage); } return isValid; } /// <summary> /// Checks Input String is valid (with logging). /// </summary> /// <param name="inputString">Input string.</param> /// <param name="errorCode">Error Code.</param> /// <param name="errorMessage">Error Message.</param> /// <returns>true or false.</returns> public static bool IsValidInputStringWithLogging(string inputString, out int errorCode, out string errorMessage) { bool isValid; (isValid, errorCode, errorMessage) = CSharp7Sample.HasValue(inputString); // deconstructing assignment - calls Deconstruct(out isValid, out errorCode, out errorMessage); if (isValid == false) { string logMessage = $"{nameof(inputString)}: {inputString}, {nameof(errorCode)}: {errorCode}, {nameof(errorMessage)}: {errorMessage}"; Console.Write(logMessage); } return isValid; } /// <summary> /// Checks Input String is valid (without logging) with discards. /// </summary> /// <param name="inputString">Input string.</param> /// <returns>true or false.</returns> public static bool IsValidInputStringWithoutLogging(string inputString) { (bool isValid, _, _) = CSharp7Sample.HasValue(inputString); // deconstructing declaration with discard. Here, we don't require "errorCode" and "errorMessage" return isValid; } /// <summary> /// Checks Input String is valid (with logging) with Deconstructor Overload. /// </summary> /// <param name="inputString">Input string.</param> /// <returns>true or false.</returns> public static bool IsValidInputStringWithLoggingWithDeconstructorOverload(string inputString) { (bool isValid, string logErrorMessage) = CSharp7Sample.HasValue(inputString); // deconstructing declaration - calls Deconstruct(out isValid, out logErrorMessage); if (isValid == false) { string logMessage = $"{nameof(inputString)}: {inputString}, {logErrorMessage}"; Console.Write(logMessage); } return isValid; } /// <summary> /// Input string has value or not. /// </summary> /// <param name="inputString">Input string.</param> /// <returns>OperationResult.</returns> private static OperationResult HasValue(string inputString) { int code = 0; string message = string.Empty; if (inputString == null) { code = 1; message = "Input string is null"; } else if (inputString.Equals(string.Empty)) { code = 2; message = "Input string is empty"; } else if (inputString.Trim().Equals(string.Empty)) { code = 3; message = "Input string only whitespaces"; } bool success = string.IsNullOrEmpty(message); var result = new OperationResult { ErrorCode = code, ErrorMessage = message, Status = success }; return result; } }
Note: Tuples enhancements needs the ValueTuple types. Add “System.ValueTuple” NuGet package on frameworks that do not include these types.
Happy Coding !!!
.NET Professional | Microsoft Certified Professional | DZone’s Most Valuable Blogger | Web Developer | Author | Blogger
Doctorate in Computer Science and Engineering
Microsoft Certified Professional (MCP) with over 12+ years of software industry experience including development, implementation & deployment of applications in the .NET framework
Experienced and skilled Agile Developer with a strong record of excellent teamwork, successful coding & project management. Specialises in problem identification and proposal of alternative solutions. Provided knowledge and individual mentoring to team members as needed
Among top 3% overall in terms of contribution on Stack Overflow (~2.3 million people reached my posts). Part of the top 1% Stack Overflow answerers in ASP.NET technology.
DZone’s Most Valuable Blogger (MVB)
Created and actively maintain the TechCartNow.com tech blog while also editing, writing, and researching topics for publication.
Excellent skills in Application Development using C#/Vb.Net, .NET Framework, ASP.NET, MVC, ADO.NET, WCF, WPF, Web API, SQL Server, jQuery, Angular, React, BackboneJS