PostSharp 4.3 / / Post­Sharp Documentation / Introduction / Quick Examples
Quick Examples

This section shows a few examples to demonstrate what PostSharp is about:

Standard patterns

PostSharp provides implementations of some of the patterns that are the most commonly found in .NET code bases:

Example

The following code snippet illustrates an object model where INotifyPropertyChanged, undo/redo, code contracts, aggregation and code contracts are all implemented using PostSharp ready-made attributes.

C#
                          [NotifyPropertyChanged]
                          

                          public
                           
                          class
                           CustomerViewModel
{
   [Required]
   
                          public
                           Customer Customer { 
                          get
                          ; 
                          set
                          ; }

   
                          public
                           
                          string
                           FullName { 
                          get
                           { 
                          return
                           
                          this
                          .Customer.FirstName + 
                          " "
                           + 
                          this
                          .Customer.LastName; } }
}

[NotifyPropertyChanged]
[Recordable]
                          

                          public
                           
                          class
                           Customer
{
   
                          public
                           
                          string
                           FirstName { 
                          get
                          ; 
                          set
                          ; }
   
                          public
                           
                          string
                           LastName { 
                          get
                          ; 
                          set
                          ; }

   [Child]
   
                          public
                           AdvisableCollection<Address> Addresses { 
                          get
                          ; 
                          set
                          ; }

   [Url]
   
                          public
                           
                          string
                           HomePage { 
                          get
                          ; 
                          set
                          ; }

   [Log]
   
                          public
                           
                          void
                           Save(DbConnection connection)
   {
      
                          // ...
                          

                             }
}

[NotifyPropertyChanged]
[Recordable]
                          

                          public
                           
                          class
                           Address
{
   [Parent]
   
                          public
                           Customer Parent { 
                          get
                          ; 
                          private
                           
                          set
                          ; }

   
                          public
                           
                          string
                           Line1 { 
                          get
                          ; 
                          set
                          ; }
}
                        
Thread safety patterns

Multi-threading is a great demonstration of the limitations of conventional object-oriented programming. Thread synchronization is traditionally addressed at an absurdly low level of abstraction, resulting in excessive complexity and defects.

Yet, several design patterns exist to bring down the complexity of multi-threading. New programming languages have been designed around these patterns: for instance Erlang over the Actor pattern and functional programming over the Immutable pattern.

PostSharp gives you the benefits of threading design patterns without leaving C# or VB.

PostSharp supports the following threading models and features:

Example

The following code snippet shows how a data transfer object can be made freezable, recursively but easily:

C#
                          [Freezable]
                          

                          public
                           
                          class
                           Customer
{
   
                          public
                           
                          string
                           Name { 
                          get
                          ; 
                          set
                          ; }

   [Child]
   
                          public
                           AdvisableCollection<Address> Addresses { 
                          get
                          ; 
                          set
                          ; }

}

[Freezable]
                          

                          public
                           
                          class
                           Address
{
   [Parent]
   
                          public
                           Customer Parent { 
                          get
                          ; 
                          private
                           
                          set
                          ; }

   
                          public
                           
                          string
                           Line1 { 
                          get
                          ; 
                          set
                          ; }
}
                          


                          public
                           
                          class
                           Program
{
   
                          public
                           
                          static
                           
                          void
                           Main()
   {
      Customer customer = ReadCustomer( 
                          "http://customers.org/11234"
                           );

      
                          // Prevent changes.
                          

                                ((IFreezable)customer).Freeze();

      
                          // The following line will cause an ObjectReadOnlyException.
                          

                                customer.Addresses[
                          0
                          ].Line1 = 
                          "Here"
                          ;
   }
}
                        
Implementation of custom patterns

The attributes that implement the standard and thread safety patterns are called aspects. This terms comes from the paradigm of aspect-oriented programming (AOP). An aspect is a class that encapsulates behaviors that are injected into another class, method, field, property or event. The process of injecting an aspect into another piece of code is called weaving. PostSharp weaves aspects at build time; it is also named a build-time aspect weaver.

PostSharp Aspect Framework is a pragmatic implementation of AOP concepts. All ready-made implementations of patterns are built using PostSharp Aspect Framework. You can use the same technology to automate the implementation of your own patterns.

To learn more about developing your own aspects, see Developing Custom Aspects.

Example

The following code snippet shows a simple [PrintException] aspect that writes an exception message to the console before rethrowing it:

C#
                          [PSerializable]
                          

                          class
                           PrintExceptionAttribute : OnExceptionAspect
{
    
                          public
                           
                          override
                           
                          void
                           OnException(MethodExecutionArgs args)
    {
        Console.WriteLine(args.Exception.Message);
    }
}
                        

In the next snippet, the [PrintException] aspect is applied to a method:

C#
                          class
                           Customer
{
    
                          public
                           
                          string
                           FirstName { 
                          get
                          ; 
                          set
                          ; }
    
                          public
                           
                          string
                           LastName { 
                          get
                          ; 
                          set
                          ; }

    [PrintException]
    
                          public
                           
                          void
                           Store(
                          string
                           path)
    {
        File.WriteAllText( path, 
                          string
                          .Format( 
                          "{0} {1}"
                          , 
                          this
                          .FirstName, 
                          this
                          .LastName ) );
    }
}
                        
Validation of custom patterns

Not all patterns can be fully implemented by the compiler. Many patterns involve a lot of hand-written code. However, they are still patterns because we want to follow the same conventions and approach when solving the same problem. In this case, we have to validate the code against implementation guidelines of the pattern. This is typically achieved during code reviews, but as any algorithmic work, it can be partially automated using the right tool. This is the job of the PostSharp Architecture Framework.

PostSharp Architecture Framework also contains pre-built architectural constraints that help solving common design problems. For instance, the InternalImplementAttribute constraint prevents an interface to be implemented in an external assembly.

See Validating Architecture for more details about architecture validation.

Example

Consider a form-processing application. There may be hundreds of forms, and each form can have dozens of business rules. In order to reduce complexity, the team decides that all business rules will respect the same pattern. The team decides that each class representing a business rule must contain a public nested class named Factory, and that this class must have an [Export(IBusinessRuleFactory)] custom attribute and a default public constructor. The team wants all developers to follow the convention. Therefore, the team decide to create an architectural constraint that will validate the code against the project-specific Business Rule Factory pattern.

C#
                          [MulticastAttributeUsage(MulticastTargets.Class, Inheritance = MulticastInheritance.Strict)] 
                          

                          public
                           
                          class
                           BusinessRulePatternValidation : ScalarConstraint 
{ 
    
                          public
                           
                          override
                           
                          void
                           ValidateCode(
                          object
                           target) 
    { 
        
                          var
                           targetType = (Type)target; 

        
                          if
                           (targetType.GetNestedType(
                          "Factory"
                          ) == 
                          null
                          ) 
        { 
            Message.Write( targetType, SeverityType.Error,  
                          "2001"
                          , 
                           
                          "The {0} type does not have a nested type named 'Factory'."
                          , 
                           targetType.DeclaringType,  targetType.Name ); 
        } 

        
                          // ...
                          

                              } 
}

[BusinessRulePatternValidation]
                          

                          public
                           
                          abstract
                           BusinessRule
{
  
                          // ...
                          

                          }