more little wonders of c#/.net

65
More “Little Wonders” of C#/.Net James Michael Hare 2012 Visual C# MVP Application Architect Scottrade August 3 rd , 2012 http://www.BlackRabbitCoder.net Twitter: @BlkRabbitCoder

Upload: blackrabbitcoder

Post on 10-May-2015

33.286 views

Category:

Technology


2 download

DESCRIPTION

We've all seen the big "macro" features in .NET, this presentation is to give praise to the "Little Wonders" of .NET -- those little items in the framework that make life as a developer that much easier!

TRANSCRIPT

Page 1: More Little Wonders of C#/.NET

More “Little Wonders” of C#/.Net

James Michael Hare2012 Visual C# MVPApplication Architect

ScottradeAugust 3rd, 2012

http://www.BlackRabbitCoder.net Twitter: @BlkRabbitCoder

Page 2: More Little Wonders of C#/.NET

Me: Blog:

http://www.BlackRabbitCoder.net Twitter: @BlkRabbitCoder

Information on Scottrade Careers: http://jobs.scottrade.com Twitter: @scottradejobs

Contact Information

Page 3: More Little Wonders of C#/.NET

The .NET Framework is full of “macro-sized” goodness that can help make our coding lives easier by automating common tasks.

But, the .NET Framework also has a lot of smaller “micro-sized” tips and tricks that can improve code.

Many developers know of most of these, but it is often surprising how many times newer developers don’t.

This presentation picks up where the first “Little Wonders” presentation leaves off…

What are “Little Wonders”?

Page 4: More Little Wonders of C#/.NET

Basically, by employing these small items at the right time, you can increase application: Readability – some of the wonders make code

much more concise and easy to read. Maintainability – often goes hand and hand with

readability, by removing ambiguity of the code, it is easier to maintain without introducing errors.

Performance – a few of the little wonders can even help increase the performance of your code (depending on usage).

How do they help?

Page 5: More Little Wonders of C#/.NET

More Little Wonders

Compiler Candy Optional/Named

Arguments Chained Constructors Generic Constraints Anonymous types

BCL Classes Enum Nullable<T> Lazy<T> Tuple Interlocked

Strings Joining Constructing

Generic Delegates Action Func

Enumerable Static Methods Empty Repeat

Collection Generators ToArray, ToList, etc.

Page 6: More Little Wonders of C#/.NET

Optional arguments allow you to specify a default value to be used if argument isn’t provided.

Default values must be compile-time constants: Numeric constant expressions String constant expressions null

Can be used to replace redundant overloads when the only purpose is to default an argument.

Optional Arguments

Page 7: More Little Wonders of C#/.NET

This…

Can replace all of these…

Page 8: More Little Wonders of C#/.NET

The default is literally compiled in at call, so this:

Is, in effect, compiled into this:

Optional Arguments

Page 9: More Little Wonders of C#/.NET

Defaults are positional, substituted from left to right:

If you want to “skip”, used named arguments:

Named Arguments

Page 10: More Little Wonders of C#/.NET

There are a couple of potential pitfalls to be aware of: If used across assemblies, can lead to subtle errors.

If a default parameter is defined in one assembly, and used in another, must make sure both get recompiled if value changes.

Default parameters are not inherited. Defaults established in an interface or base-class do not

directly apply (and can be different from) the sub-class. Default depends on reference type, not the object type.

Default Parameters

Page 11: More Little Wonders of C#/.NET

Constructors can call each other directly, which can reduce the need for redundant code in overloads.

You could use optional arguments or initializers to reign in overloads, but each have their limitations: Optional arguments must be set to compile-

time constant expressions. Initializers aren’t suitable for immutable

classes, readonly fields, get-only properties, or items whose construction may be “heavy”.

Chained Constructors

Page 12: More Little Wonders of C#/.NET

Consider this:

Page 13: More Little Wonders of C#/.NET

Can simplify by chaining constructors:

Page 14: More Little Wonders of C#/.NET

Generics allow you to make very powerful types and algorithms, but can be a two-edged sword.

An unconstrained generic type parameter makes no assumptions, giving you the lowest common denominator of all types.

Supplying a constraint reduces the types that can be used to realize the generic, but expands the things that can be done inside the generic.

Generic Constraints

Page 15: More Little Wonders of C#/.NET

For example, how would unconstrained T handle null?

Unconstrained T can be compared to null, but this is always false for value types (except Nullable<T>).

Unconstrained T cannot be assigned to null, though can be assigned to default(T).

Generic Constraints

Page 16: More Little Wonders of C#/.NET

Or constrain T to be a value type (for example, since Nullable<T> can only support value types…

Generic Constraints

Page 17: More Little Wonders of C#/.NET

Generic Constraints

Or what if we want to create a new unconstrained T instance, or access any of T’s members?

Can’t, no way to know if unconstrained T supports parameter-less construction or other members.

Generic Constraints

Page 18: More Little Wonders of C#/.NET

Supplying a constraint constrains the matching types, but also expands what you can do with the generic: where T : struct – T must be a value type, must be first.

Allows T to be used in other value generics (Nullable<T>, etc.).

where T : class – T must be a reference type, must be first. Allows T to be assigned to null in generic.

where T : U – T must be, inherit, or implement U Allows T to access any public members of U in generic.

where T : new() – T must have a public parameter-less constructor, must be last Allows T to be constructed in generic.

Generic Constraints

Page 19: More Little Wonders of C#/.NET

Constraining T to things that implement IDictionary and have parameter-less constructor:

Generic Constraints

Page 20: More Little Wonders of C#/.NET

Constraining T only value types that implement IConvertible:

Generic Constraints

Page 21: More Little Wonders of C#/.NET

We can construct and initialize any type on the fly using object initialization syntax:

Anonymous Types

Page 22: More Little Wonders of C#/.NET

What if we only need a type for a very localized purpose? Why create the boilerplate code for a class

that will only be used in a small, localized section?

Most of these classes are simple POCOs, is it worth a full definition?

If you need to use a type as a key (equality, hashing), it can get heavy. Must implement Equals() and GetHashCode()

correctly.

Anonymous Types

Page 23: More Little Wonders of C#/.NET

How would we define UserDay, UserDayTotal?

Page 24: More Little Wonders of C#/.NET

Not as trivial as would think…

Page 25: More Little Wonders of C#/.NET

Anonymous types create throw-away types for you: Creates type based on name, type, order of

properties. Creates suitable Equals() and

GetHashCode(). Syntax is like object initialization, just omit

type name.

Anonymous Types

Page 26: More Little Wonders of C#/.NET

Now, much simpler… Don’t need to define UserDay or UserDayTotal Don’t need to maintain Equals() and

GetHashCode(). Doesn’t clutter up project with throw-away

types.

Anonymous Types

Page 27: More Little Wonders of C#/.NET

A few things to be aware of: Type is generated at compile time based on

properties’ names, types, order – any deviation is a different type:

Difficult to use outside of defined scope (which shouldn’t do anyway, defeats purpose).

Anonymous Types

Page 28: More Little Wonders of C#/.NET

Enum is not only the base of enums, it also has several useful static methods: IsDefined() – Determines if an enum

constant exists with the given value. HasFlag() – Determines if a given set of bits is

set, much easier to read than the typical bitwise AND.

TryParse() – Parse a string value into enum value, much lighter than Parse().

The Enum Class

Page 29: More Little Wonders of C#/.NET

Use IsDefined() to see if a value exists

And HasFlag() simplifies flag testing:

The Enum Class

Page 30: More Little Wonders of C#/.NET

The TryParse() is much lighter than Parse(), especially if you think you may not have a valid value:

The Enum Class

Page 31: More Little Wonders of C#/.NET

You can indicate an optional value easily with null for reference types, but value types always exist.

Sometimes, appropriate sentinel values don’t exist.

The Nullable<T> generic struct simulates optional values for value types.

Nullable<T> has two key properties: HasValue – True if Value has been set to a value. Value – The value if set, throws if not.

The Nullable<T> Struct

Page 32: More Little Wonders of C#/.NET

Use when you have a value type which may or may not contain a valid value.

For example, the DateTime struct’s default value isn’t very meaningful, use DateTime? Instead.

The Nullable<T> Struct

Page 33: More Little Wonders of C#/.NET

We then must test to make sure it has a value by using HasValue property.

Once we know the value exists, access Value to retrieve it.

The Nullable<T> Struct

Page 34: More Little Wonders of C#/.NET

Nullable<T> allows some syntactical shortcuts: Nullable<T> can be abreviated T?

Nullable<T> can be assigned to null

Nullable<T> can be compared with null

The Nullable<T> Struct

Page 35: More Little Wonders of C#/.NET

Some things to watch out for: Nullable<T> doesn’t save space if value not

specified, still stores a Value, it’s just not usable.

Accessing Value when HasValue is not true is an error and will throw an exception.

Math or logical operations between Nullable<T> wrapped numeric types (int, double, etc.) has caveats: Math with null yields null. Logical ordered comparison with null yields

false.

The Nullable<T> Struct

Page 36: More Little Wonders of C#/.NET

Some classes may be expensive to create, especially if they are not always needed, in these cases lazy instances are often used.

No need to create your own lazy-initialization logic anymore, Lazy<T> does it all for you.

Can either call default constructor, or a generator.

Various thread-safety modes so you can choose the level of performance and safety you require.

The Lazy<T> Class

Page 37: More Little Wonders of C#/.NET

Lazy<T>

Constructor not called until Value accessed.

Page 38: More Little Wonders of C#/.NET

If a constructor isn’t accessible, or desired, you can always use a factory method:

Lazy<T>

Page 39: More Little Wonders of C#/.NET

By default, Lazy<T> is thread-safe, but can choose:

Lazy<T>

Page 40: More Little Wonders of C#/.NET

Sometimes, you need to just throw together several values to treat as a set of values.

Tuples allow you to do this in a generic way. Similar to anonymous types, yet different:

Both are immutable and have Equals(), GetHashCode()

Anonymous types have named properties, but not type.

Tuples have generic property names, but named type. Tuple has static factory methods to easy creation.

The Tuples

Page 41: More Little Wonders of C#/.NET

The Tuples

Simple tuples are a single “layer” and have properties numbered Item1…Item7:

Page 42: More Little Wonders of C#/.NET

Get longer Tuples by using octuple, which has TRest:

Tuples

Page 43: More Little Wonders of C#/.NET

Locking to safely increment a count is heavy:

Interlocked

Page 44: More Little Wonders of C#/.NET

Allows thread-safe, highly performant manipulation of numeric values.

Much lighter than full locks for simple operations like: Increment – adds 1 to the interlocked value Decrement – subtracts 1 from the interlocked

value Exchange – swaps two values Add – adds a value to the interlocked value

Interlocked

Page 45: More Little Wonders of C#/.NET

Using interlocked, we can do the same thing, without heavy locks:

Interlocked

Page 46: More Little Wonders of C#/.NET

Have you ever seen someone construct an array of repeated char like this?

Instead, quickly create a string of a repeated character using one of string’s constructors:

Strings of Repeated Char

Page 47: More Little Wonders of C#/.NET

Many times people write code to do this:

When they can simply do a Join():

Joining Strings

Page 48: More Little Wonders of C#/.NET

The string.Join() has a lot of power Can Join any array or IEnumerable<T>:

Can join a variable argument list, including mixed types:

Joining Strings

Page 49: More Little Wonders of C#/.NET

One of the oldest patterns in the OO playbook is to create a class that is 99% complete except for one anonymous “work” method, which is typically abstract…

Generic Delegates

Page 50: More Little Wonders of C#/.NET

Like this…

Page 51: More Little Wonders of C#/.NET

Inheriting from a class simply to provide a missing method per use is often overkill and poor coupling.

Can’t easily change behavior at runtime. Bloats projects with classes that just

override.

Generic Delegates

Page 52: More Little Wonders of C#/.NET

We can instead provide behavior through a delegate. Behavior can be added with no extra subclasses

needed. There is very limited coupling between the delegate

and the class/method using it. Behavior could be changed out at runtime.

But defining a new delegate each time gets ugly:

Generic delegates can be used for most delegate needs.

Generic Delegates

Page 53: More Little Wonders of C#/.NET

Action is a generic family of delegates that take up to 16 arguments and return nothing: Action – takes zero arguments, returns

nothing Action<T> - takes one argument, returns

nothing. Action<T1, T2> - takes two arguments,

returns nothing. … Action<T1…T16> - takes 16 arguments,

returns nothing. Action cannot be used for ref or out

arguments.

The Action Delegate

Page 54: More Little Wonders of C#/.NET

Similar to Action, but Func returns a value: Func<TResult> – takes zero args, returns a TResult. Func<T, TResult> - takes one arg, returns a TResult. Func<T1, T2, TResult> - takes two args, returns a TResult.

… Func<T1…T16, TResult> - takes 16 args, returns a TResult.

Func cannot be used for ref or out arguments. Func<T, bool> is generally preferable to

Predicate<T>.

The Func Delegate

Page 55: More Little Wonders of C#/.NET

Revised Consumer:

Page 56: More Little Wonders of C#/.NET

How many times have you created an empty array or List<T> to represent an empty sequence?

Empty Enumerables

Page 57: More Little Wonders of C#/.NET

Enumerable has a static method Empty<T>() that generates a singleton empty IEnumerable<T>.

Empty Enumerable

Page 58: More Little Wonders of C#/.NET

Allows you to create a sequence of the same item a given number of times.

Doesn’t recreate the item each time, takes whatever the parameter is and creates a sequence.

For example, to create 10 random numbers:

Enumerable Repeat

Page 59: More Little Wonders of C#/.NET

Often times you’ll have a sequence and want to store in a collection to: Avoid re-generating the sequence during

multiple iterations. Convert the sequence from one sequence type

to another. Pull the sequence into a collection to avoid

deferred execution issues.

Collection Generators

Page 60: More Little Wonders of C#/.NET

There are several LINQ extension methods to generate different collections from sequences: ToArray() – stores sequence in a T[]. ToList() – stores sequence in a List<T>. ToDictionary() – transforms sequence to a

Dictionary<TKey, TValue> given selectors for TKey and TValue.

ToLookup() – transforms sequence to a Lookup<TKey, TValue> - similar to dictionary but can have repeated keys.

Collection Generators

Page 61: More Little Wonders of C#/.NET

ToArray() and ToList() are useful for: Remove effects of deferred execution. Convert a sequence to a particular kind.

ToArray and ToList

Page 62: More Little Wonders of C#/.NET

ToDictionary() converts a linear sequence to a Dictionary that maps a single key to a single value. Keys can only exist once, multiple key

instances throw. Must provide key selector, value selector

optional.

ToDictionary

Page 63: More Little Wonders of C#/.NET

ToLookup() is similar to ToDictionary(), but it maps a key to a set of values (essentially a multi-map). Again must provide key selector, value

optional.

ToLookup

Page 64: More Little Wonders of C#/.NET

Questions?

Page 65: More Little Wonders of C#/.NET

Platinum Sponsors

Silver Sponsors

Gold Sponsors