15 features worth knowing about .NET developers

This article lists 15 C# features worth knowing, designed to make .NET developers better at developing with the C# language.

1. ObsoleteAttribute

ObsoleteAttribute applies to all program elements except components, modules, parameters, and return values. Marking an element as obsolete informs the user that the element will be removed in a future version.
IsError - set to true, the compiler will raise an error when using this property in code.

public static class ObsoleteExample
{
    // Mark OrderDetailTotal As Obsolete.
    [ObsoleteAttribute("This property (DepricatedOrderDetailTotal) is obsolete.
                       Use InvoiceTotal instead.", false)]
    public static decimal OrderDetailTotal
    {
        get
        {
            return 12m;
        }
    }

    public static decimal InvoiceTotal
    {
        get
        {
            return 25m;
        }
    }

    // Mark CalculateOrderDetailTotal As Obsolete.
    [ObsoleteAttribute("This method is obsolete. Call CalculateInvoiceTotal instead.", true)]
    public static decimal CalculateOrderDetailTotal()
    {
        return 0m;
    }

    public static decimal CalculateInvoiceTotal()
    {
        return 1m;
    }
}

If we use the above classes in our code, errors and warnings are displayed.

Console.WriteLine(ObsoleteExample.OrderDetailTotal);
Console.WriteLine( );
Console.WriteLine(ObsoleteExample.CalculateOrderDetailTotal());

Official Documentation -  https://msdn.microsoft.com/en-us/library/system.obsoleteattribute.aspx

 

2. Use DefaultValueAttribute to set default value for C# auto-implemented property

DefaultValueAttribute can specify the default value of the attribute. You can use DefaultValueAttribute to create any value. The default value of a member is usually its initial value.

This property cannot be used to automatically initialize object members with specific values. Therefore, the developer must set the initial value in the code.

public class DefaultValueAttributeTest
{
    public DefaultValueAttributeTest()
    {
        // Use the DefaultValue property of each property to actually set it, via reflection.
        foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(this))
        {
            DefaultValueAttribute attr = (DefaultValueAttribute)prop.Attributes
                                         [typeof(DefaultValueAttribute)];
            if (attr != null)
            {
                prop.SetValue(this, attr.Value);
            }
        }
    }

    [DefaultValue(25)]
    public int Age { get; set; }

    [DefaultValue("Anton")]
    public string FirstName { get; set; }

    [DefaultValue("Angelov")]
    public string LastName { get; set; }

    public override string ToString()
    {
        return string.Format("{0} {1} is {2}.", this.FirstName, this.LastName, this.Age);
    }
}

Auto-implemented properties are initialized by reflection in the class's constructor. The code iterates over all properties of the class and sets them to default values.

Official Documentation -  https://msdn.microsoft.com/en-US/library/system.componentmodel.defaultvalueattribute.aspx

 

3. DebuggerBrowsableAttribute

The DebuggerBrowsableAttribute is used to determine if and how to display member variables in the debugger variables window.

public static class DebuggerBrowsableTest
{
    private static string squirrelFirstNameName;
    private static string squirrelLastNameName;

    // The following DebuggerBrowsableAttribute prevents the property following it
    // from appearing in the debug window for the class.
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public static string SquirrelFirstNameName
    {
        get
        {
            return squirrelFirstNameName;
        }
        set
        {
            squirrelFirstNameName = value;
        }
    }

    [DebuggerBrowsable(DebuggerBrowsableState.Collapsed)]
    public static string SquirrelLastNameName
    {
        get
        {
            return squirrelLastNameName;
        }
        set
        {
            squirrelLastNameName = value;
        }
    }
}

Official Documentation -  https://msdn.microsoft.com/en-US/library/system.diagnostics.debuggerbrowsableattribute.aspx

 

4. ?? operator

The ?? operator returns the left operand when the left operand is non-null, otherwise returns the right operand. The ?? operator is defined as the default value to return when assigning a nullable type to a non-nullable type.

int? x = null;
int y = x ?? -1;
Console.WriteLine("y now equals -1 because x was null => {0}", y);
int i = DefaultValueOperatorTest.GetNullableInt() ?? default(int);
Console.WriteLine("i equals now 0 because GetNullableInt() returned null => {0}", i);
string s = DefaultValueOperatorTest.GetStringValue();
Console.WriteLine("Returns 'Unspecified' because s is null => {0}", s ?? "Unspecified");

Official Documentation -  https://msdn.microsoft.com/en-us/library/ms173224(v=vs.80).aspx

 

5. Curry and Partial methods

Curry - In mathematics and computer science, currying is a technique of transforming the evaluation of a function into multiple arguments (or tuples of arguments), primarily for evaluating a sequence of functions, each with one argument.

To implement via C#, use the functionality of extension methods .

public static class CurryMethodExtensions
{
    public static Func<A, Func<B, Func<C, R>>> Curry<A, B, C, R>(this Func<A, B, C, R> f)
    {
        return a => b => c => f(a, b, c);
    }
}


Func<int, int, int, int> addNumbers = (x, y, z) => x + y + z;
var f1 = addNumbers.Curry();
Func<int, Func<int, int>> f2 = f1(3);
Func<int, int> f3 = f2(4);
Console.WriteLine(f3(5));

The types returned by different methods can be swapped with the  var  keyword.

Official Documentation -  https://en.wikipedia.org/wiki/Currying#/Contrast_with_partial_function_application

Partial - In computer science, Partial application (or Partial function application) refers to the process of fixing some parameters to a function, resulting in another smaller function.

public static class CurryMethodExtensions
{
    public static Func<C, R> Partial<A, B, C, R>(this Func<A, B, C, R> f, A a, B b)
    {
        return c => f(a, b, c);
    }
}

The use of Partial extension methods is more straightforward than Curry.

Func<int, int, int, int> sumNumbers = (x, y, z) => x + y + z;
Func<int, int> f4 = sumNumbers.Partial(3, 4);
Console.WriteLine(f4(5));

Official Documentation -  https://en.wikipedia.org/wiki/Partial_application

 

6. WeakReference

Weak references allow the application to access the object while it is being collected by the collector. If you need the object, you can still get a strong reference and prevent it from being collected.

WeakReferenceTest hugeObject = new WeakReferenceTest();
hugeObject.SharkFirstName = "Sharky";
WeakReference w = new WeakReference(hugeObject);
hugeObject = null;
GC.Collect();
Console.WriteLine((w.Target as WeakReferenceTest).SharkFirstName);

If the garbage collector is not explicitly called, there is still a good chance that weak references will be allocated.

Official Documentation -  https://msdn.microsoft.com/en-us/library/system.weakreference.aspx

 

7. Lazy<T>

Using lazy initialization, you can defer the creation or execution of a specified class for the lifetime of a program when creating a large resource-intensive object or performing a resource-intensive task.

public abstract class ThreadSafeLazyBaseSingleton<T>
    where T : new()
{
    private static readonly Lazy<T> lazy = new Lazy<T>(() => new T());
    
    public static T Instance
    {
        get
        {
            return lazy.Value;
        }
    }
}

Official Documentation -  https://msdn.microsoft.com/en-us/library/dd642331(v=vs.110).aspx

 

8. BigInteger

The BigInteger type is an immutable type that represents an arbitrarily large integer whose value theoretically has no upper or lower bound. Unlike other integral types in the .NET Framework, this type has a range indicated by its own MinValue and MaxValue properties.

Note: Because the BigInteger type is immutable, and because it has no upper or lower bound, an OutOfMemoryException is thrown for any operation that causes the BigInteger value to become too large.

string positiveString = "91389681247993671255432112000000";
string negativeString = "-90315837410896312071002088037140000";
BigInteger posBigInt = 0;
BigInteger negBigInt = 0;

posBigInt = BigInteger.Parse(positiveString);
Console.WriteLine(posBigInt);
negBigInt = BigInteger.Parse(negativeString);
Console.WriteLine(negBigInt);

Official Documentation -  https://msdn.microsoft.com/en-us/library/system.numerics.biginteger(v=vs.110).aspx

 

9. C# keywords without official documentation (__arglist/__reftype/__makeref/__refvalue)

Some C# keywords are not officially documented, and the reason for the lack of documentation may be that these keywords have not been fully tested. However, these keywords have been colored by the Visual Studio editor and recognized as official keywords.

You can use the __makeref keyword to create a typed reference in a variable, use the __reftype keyword to extract the original type of the variable represented by the typed reference, obtain parameter values ​​from a TypedReference using the __refvalue keyword, and use __arglist to access parameter list.

int i = 21;
TypedReference tr = __makeref(i);
Type t = __reftype(tr);
Console.WriteLine(t.ToString());
int rv = __refvalue( tr,int);
Console.WriteLine(rv);
ArglistTest.DisplayNumbersOnConsole(__arglist(1, 2, 3, 5, 6));

The ArglistTest class is required when using __arglist.

public static class ArglistTest
{
    public static void DisplayNumbersOnConsole(__arglist)
    {
        ArgIterator ai = new ArgIterator (__ arglist);
        while (ai.GetRemainingCount() > 0)
        {
            TypedReference tr = ai.GetNextArg();
            Console.WriteLine(TypedReference.ToObject(tr));
        }
    }
}

References -  http://www.nullskull.com/articles/20030114.asp and http://community.bartdesmet.net/blogs/bart/archive/2006/09/28/4473.aspx

 

10. Environment.NewLine

Get the newline string in the current environment.

Console.WriteLine("NewLine: {0}  first line{0}  second line{0}  third line", Environment.NewLine);

Official Documentation -  https://msdn.microsoft.com/en-us/library/system.environment.newline(v=vs.110).aspx

 

11. ExceptionDispatchInfo

Holds a caught exception in the code. You can use the ExceptionDispatchInfo.Throw method, which is in the System.Runtime.ExceptionServices namespace. This method can be used for calling procedures that raise an exception and preserve the original stack.

ExceptionDispatchInfo possibleException = null;
try
{
    int.Parse("a");
}
catch (FormatException ex)
{
    possibleException = ExceptionDispatchInfo.Capture(ex);
}

if (possibleException != null)
{
    possibleException.Throw();
}

A caught exception can be thrown again in another method or another thread.

Official Documentation -  https://msdn.microsoft.com/en-us/library/system.runtime.exceptionservices.exceptiondispatchinfo(v=vs.110).aspx

 

12. Environment.FailFast()

If you want to exit the program without calling any finally blocks or finalizers, you can use FailFast.

 
string s = Console.ReadLine();
try
{
    int i = int.Parse(s);
    if (i == 42) Environment.FailFast("Special number entered");
}
finally
{
    Console.WriteLine("Program complete.");
}

If i is equal to 42, the finally block will not be executed.

Official Documentation -  https://msdn.microsoft.com/en-us/library/ms131100(v=vs.110).aspx

 

13. Debug.Assert&Debug.WriteIf&Debug.Indent

Debug.Assert is used to check the condition, and if the condition is false, output a message and display a message box showing the call stack.

Debug.Assert(1 == 0, "The numbers are not equal! Oh my god!");

If an assertion fails in debug mode, the following alert is displayed with the specified message.

Debug.WriteIf - If true, writes information about debugging to the trace listeners in the Listeners collection.

Debug.WriteLineIf(1 == 1, "This message is going to be displayed in the Debug output! =)");

Debug.Indent/Debug.Unindent - Causes the IndentLevel to increment by one.

Debug.WriteLine("What are ingredients to bake a cake?");
Debug.Indent();
Debug.WriteLine("1. 1 cup (2 sticks) butter, at room temperature.");
Debug.WriteLine("2 cups sugar");
Debug.WriteLine("3 cups sifted self-rising flour");
Debug.WriteLine("4 eggs");
Debug.WriteLine("1 cup milk");
Debug.WriteLine("1 teaspoon pure vanilla extract");
Debug.Unindent();
Debug.WriteLine("End of list");

If you want to display the ingredients of cake in the debug output window, you can use the above code.

官方文档:Debug.AssertDebug.WriteIfDebug.Indent / Debug.Unindent

 

14. Parallel.For&Parallel.Foreach

Parallel.For - executes a for loop that can run iterations in parallel.

int[] nums = Enumerable.Range(0, 1000000).ToArray();
long total = 0;

// Use type parameter to make subtotal a long, not an int
Parallel.For<long>(0, nums.Length, () => 0, (j, loop, subtotal) =>
{
    subtotal += nums[j];
    return subtotal;
},
    (x) => Interlocked.Add(ref total, x)
);

Console.WriteLine("The total is {0:N0}", total);

The Interlocked.Add method adds two integers and replaces the first integer with the sum.

Parallel.Foreach - performs a foreach operation that can run iterations in parallel.

int[] nums = Enumerable.Range(0, 1000000).ToArray();
long total = 0;

Parallel.ForEach<int, long>(nums, // source collection
                            () => 0, // method to initialize the local variable
    (j, loop, subtotal) => // method invoked by the loop on each iteration
    {
        subtotal += j; //modify local variable
        return subtotal; // value to be passed to next iteration
    },
    // Method to be executed when each partition has completed.
    // finalResult is the final value of subtotal for a particular partition.
(finalResult) => Interlocked.Add(ref total, finalResult));

Console.WriteLine("The total from Parallel.ForEach is {0:N0}", total);

Official documentation: Parallel.For  and  Parallel.Foreach

 

15. IsInfinity

Returns a value indicating whether a number is negative or positive infinity.

Console.WriteLine("IsInfinity(3.0 / 0) == {0}.", Double.IsInfinity(3.0 / 0) ? "true" : "false");

Official Documentation -  https://msdn.microsoft.com/en-us/library/system.double.isinfinity(v=vs.110).aspx

Original link: https://www.codeproject.com/Articles/1021335/Top-Underutilized-Features-of-NET

Please indicate the source of the reprint: Grape City Controls

 

C# development tool recommendation

ComponentOne Studio Enterprise  is a .NET full-featured control package focused on enterprise applications, supporting multiple platforms such as WinForms, WPF, UWP, ASP.NET MVC, etc., helping to deliver rich desktop, web and mobile in advance while reducing costs Enterprise applications. The control supports a wide range, including table and data management, chart and data visualization, popular UI interface, etc., providing high-performance control tools for enterprise application development.

 

About Grape City

Founded in 1980, Grape City is the world's leading software and service provider integrating development tools, business intelligence solutions, and management system design tools. Xi'an Grape City is its branch in China, providing software R&D services to the global market, and international advanced development tools, software and R&D consulting services for the informatization of Chinese enterprises.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326228610&siteId=291194637