User Control vs Custom Control

Custom Control

  • Extends or creates an entirely custom, usually complex, control
  • Derives from Control or any of its subclasses
  • Usually has a pluggable interface
  • Usually defined in C# with a style inside the theme resource dictionary
  • Includes implementation and usually default template interface and style, but expected to be changed/skinned on by consumer

 User Control

Rx ReplaySubject

  • ReplaySubject is a Subject with memory
  • It can have temporal or spacial memory:
    • Construct it with an int and it will have a buffer of that size
    • Constuct it with a TimeSpan and it will have a buffer of that duration
    • Construct it with both and it will have both
  • It’s main use is when publishes occur before subscriptions, and some history is required
  • ReplaySubject(1) can be used to pass in a dependency as IObservable<FooDependency>
    • Useful when the creation of FooDependency is potentially long running
    • And when useful work can be done without FooDependency (e.g. bring up a UI or load other modules
ReplaySubject<T> Class

Default empty delegate “no-op” event

Assigning a default empty delegate to an event on declaration like so

public event EventHandler FooEvent = delegate { };

+ Cannot cause a NullReferenceException by doing FooEvent(sender, args), as always at least one event subscriber

+ No need for null check, which makes code intent clearer

– Uses extra memory to create this empty event handler which is always called but never does anything useful

– Bypasses well known code pattern, which may confuse people later

if (FooEvent != null)

{

    FooEvent(this, BarArgs);

}

Namespaces

A namespace is a high level way of defining scope

  • Namespaces implicitly always have public scope
  • Everything within a namespace must have a unique name so this name, together with the namespace, unambiguously identifies it
  • Namespaces can be nested
  • The using keyword imports a namespace for use without explicitely prepending it
  • Aliases can be given to namespaces for clarity e.g. using Comms = Provider.Project.CommunicationLayer
  • If something like a locally scoped class is hiding the desired namespace, the global keyword can be used to reference the root namespace e.g. global::System.Console.WriteLine(“hello”)

var vs. dynamic

Both var and dynamic can be used to declare an object of undefined type.

var

  • Is implicitly strongly typed – the variable is truly of one single type and cannot be anything else.
  • Is statically bound – bound to a type at compile time.
  • Compiles to exactly the same code as if it was explicitly typed.
  • Is type safe – operations are checked at run time to ensure they are available to be performed on the specific type


dynamic

  • Is implicitly weakly typed – it can become an object of any type, determined only at run time.
  • Is dynamically bound – bound to a type at run time.
  • Compiles to complex dynamic code, with a subsequent run time performance hit.
  • Is not type safe – operations cannot be checked until run time as only then is the type determined.
  • It differs from the Object type in that it is (eventually) bound to a type – no casts are required to call methods.

So var is a useful time saver when you don’t know or care which type a variable will be. dynamic is a more complex tool for when it cannot be known which type it will be until run time.

Sealed modifier

The sealed modifier is used to stop classes further down an object hierarchy from overriding implementations

  • It can be used on classes, methods and properties
  • Sealed methods and properties must also be declared override and override a virtual method or property
  • You may seal an entire base class, but not methods or properties within a base class (as they need to override virtual member)
  • Sealing an abstract would make it unusable and results in an error
  • Error CS0239 will be thrown at compile time if you attempt to override a sealed member

Dispose() vs Finalize()

Both Dispose() and Finalize():

  • Should be implemented for objects which hold references to unmanaged resources (file handles, network connections, COM objects etc) to ensure the memory is freed up after use

Dispose()

  • Member of the IDisposable interface
  • Should be public
  • Should be called as soon as the unmanaged resources are no longer required
  • Should call its parents Dispose method
  • Should be callable multiple times
  • Should call GC.SuppressFinalize(this) to ensure the expensive (and now redundant) Finalize method is not called later
  • Is the method called at the end of a using statement

Finalize()

  • Should be protected
  • Should only be used by the Garbage Collector as a backup, in case the Dispose method isn’t called
  • Should call it’s parents Finalize method