Tuesday, April 22, 2008

Creating a database dependency for Enterprise Library caching block

The Caching Application Block ships with four expiration policies out of which three are time based expiration policies and one is a notification based expiration policy. This article focuses on creating a notification based expiration policy for Caching application block to create a database dependency for the cached items.

The only notification based expiration policy that ships along with the caching application block is a FileBasedExpiration policy. If you need to implement any other notification based expiration policy for your application you need to implement the ICacheItemExpiration interface shipped along with the Caching Application Block. The ICacheItemExpiration interface has three method signatures defined.

public interface ICacheItemExpiration

{

bool HasExpired();

void Initialize(CacheItem owningCacheItem);

void Notify();

}

In this article I will explain how you can create a custom expiration policy for creating a database dependency for your caching application block that used the data access application block also.

When you need to cache the master data for an enterprise application that exists in a database, a useful notification-based expiration would be one that will remove a cached item based on modifications that are made to a database table. If you look into the enterprise library notification policies, you will find that no notification policy is defined for changes made to database tables. We need to create a custom notification policy by implementing the ICacheItemExpiration interface to create a DataBaseDependecyNotification.

The DataBaseDependecyNotification class should implement the HasExpired method that returns a Boolean value based on the modifications made. I have implemented the method as follows.

public Boolean HasExpired()

{

Boolean expired = false;

try

{

DateTime lastChangedDate = DateTime.MinValue;

Database db = DatabaseFactory.CreateDatabase("ConnectionString");

using (IDataReader dataReader = db.ExecuteReader("GetLastModifiedDate", dependencyTableName))

{

if (dataReader.Read())

lastChangedDate = dataReader.IsDBNull(0) ? DateTime.MinValue : dataReader.GetDateTime(0);

}

if (tableChangedDate.Equals(DateTime.MinValue))

{

tableChangedDate = lastChangedDate;

}

if (tableChangedDate.Equals(lastChangedDate) == false)

{

tableChangedDate = lastChangedDate;

expired = true;

}

}

catch (Exception ex)

{

throw new ArgumentException("Failed to retirieve the last modified date from database " + ex.Message);

}

return expired;

}

In the database you need to create a ChangeLog table that will hold the details of the Master tables and the changed date for the tables.

Column

DataType

TableName

nvarchar(250)

ChangeID

int

ModifiedDate

datetime

The next step is to create triggers for the master tables that will update the ChangeLog table that I have created for tracking the data changes.

CREATE TRIGGER [dbo].[MasterTableNotificationTrigger]

ON [dbo].[MasterTable]

FOR INSERT, UPDATE, DELETE

AS

BEGIN

SET NOCOUNT ON

DECLARE @TableCount INT

SELECT @TableCount = Count(*) FROM [dbo].[ChangeLog] WHERE TableName = 'MasterTable'

IF(@TableCount <> 0)

UPDATE [dbo].[ChangeLog] WITH (ROWLOCK) SET ChangeID = ChangeID + 1, ModifiedDate = GetDate() WHERE TableName = 'MasterTable'

ELSE

INSERT INTO [dbo].[ChangeLog]

(TableName, ChangeID)

VALUES

('MasterTable', 0)

END

The last step is to write the procedure that is called from the notification class.

ALTER PROCEDURE [dbo].[GetLastModifiedDate]

@TableName varchar(250)

AS

BEGIN

SET NOCOUNT ON;

Declare @TableNameCount int

SELECT @TableNameCount = COUNT(*) FROM ChangeLog WHERE TableName = @TableName

SELECT ModifiedDate

From ChangeLog

Where TableName = @TableName

END

Now you can add the database dependency into the caching layer while inserting items into the cache like.

cacheManager.Add(key, item,

CacheItemPriority.Normal, new CacheRefreshPolicy(),

new DatabaseDependencyNotification(TableName));

Thursday, April 17, 2008

Sorting and Grouping in LINQ to Objects

As a continuation to the articles on LINQ, in this post I will explain how to write queries and use the query operators to perform common operations such as sorting, dealing with nested data, and grouping.

For the examples used in this article I will use the following data model.

public class Customer

{

public String Name { get; set; }

public Int32 Age { get; set; }

public Collection<Address> Addresses { get; set; }

public String Industry { get; set; }

}

public class Address

{

public String AddressLine { get; set; }

public String Country { get; set; }

}

And the method to return the data as

private static Collection<Customer> GetCustomers()

{

return new Collection<Customer> {

new Customer { Name = "John Samuels", Age = 40 , Addresses = new Collection<Address>

{ new Address { AddressLine = "New York", Country = "USA" },

new Address { AddressLine = "California, 21st Main Road", Country = "USA" },

new Address { AddressLine = "London", Country= "UK" }

}, Industry = "Computers"},

new Customer { Name = "Sreejith P.R", Age = 30 , Addresses = new Collection<Address>

{ new Address { AddressLine = "Bangalore", Country = "India" },

new Address { AddressLine = "Redmond", Country = "USA" }

}, Industry = "Telecom"},

new Customer { Name = "Kim David", Age = 35 , Addresses = new Collection<Address>

{ new Address { AddressLine = "Shangai", Country = "China" }

}, Industry = "Telecom"},

new Customer { Name = "Rahul Bose", Age = 50 , Addresses = new Collection<Address>

{ new Address { AddressLine = "New York", Country = "USA" },

new Address { AddressLine = "Bangalore", Country = "India" },

new Address { AddressLine = "Mysore", Country= "India" },

new Address { AddressLine = "Kolkatta", Country= "India" }

}, Industry = "Information Technology"},

new Customer { Name = "Micheal Johnson", Age = 37 , Addresses = new Collection<Address>

{ new Address { AddressLine = "New York", Country = "USA" },

new Address { AddressLine = "London", Country= "UK" }

}, Industry = "Computers"}

};

}

Now let’s say we want to see the customers in USA, sorted by their names in descending order.

The query I wrote to achieve this result is

var customers = (from customer in GetCustomers()

from address in customer.Addresses

where address.Country == "USA"

orderby customer.Name descending

select customer.Name).Distinct();

The operator that we are interested here is the orderby operator which sorts the collection in ascending order by default. You can also use the descending, ThenByDescending, ThenBy, OrderByDescending operators also for sorting.

The groupby operator helps you to group the query result based on any grouping condition.

For example to display all the customers grouped by industry we write the query like.

var industryCustomers =

from customer in GetCustomers()

group customer by customer.Industry into customerIndustries

select new { Industry = customerIndustries.Key, Customers = customerIndustries };

You can also have the advantage of using aggregation operators after grouping the results.

For example to find the minimum age of each customer by each industry we can write the query like.

var industryCustomers =

from customer in GetCustomers()

group customer by customer.Industry into customerIndustries

select new { Industry = customerIndustries.Key, Customers = customerIndustries, MinAge = customerIndustries.Min(cust => cust.Age)};

Wednesday, April 16, 2008

Deffered query execution in LINQ

LINQ improves performance by deferring the execution of the query until it is actually needed. One of the most important features of LINQ is the lazy evaluation of the query. It is this property that makes LINQ to improve performance while querying the collections.

Consider the following example:

private static Collection<User> GetUsers()

{

return new Collection<User> {

new User { UserName = "Sreejith P.R", Salary = 5000, Country = "India" },

new User { UserName = "John Samuels", Salary = 3450, Country = "UK" },

new User { UserName = "Kemp Davis", Salary = 6733, Country = "USA" },

new User { UserName = "Rahul Bose", Salary = 9000, Country = "India"},

new User { UserName = "Micheal Johnson", Salary = 4566, Country = "USA"},

new User { UserName = "Kim David", Salary = 7822, Country = "Denmark"}

};

}

static Int32 IncreaseSalary(Int32 salary)

{

Console.WriteLine("\nIncreasing Salary...");

return salary + 2000;

}

static void Main(string[] args)

{

var userSalaries =

from user in GetUsers()

where user.Salary > 5000 //Execute when the foreach statment is called.

select new { Name = user.UserName,

Salary = IncreaseSalary(user.Salary) };

foreach (var user in userSalaries)

{

Console.WriteLine(user.Name + " " + user.Salary.ToString());

}

Console.ReadKey();

}

The output of this sample is

Increasing Salary... Kemp Davis 8733

Increasing Salary... Rahul Bose 11000

Increasing Salary... Kim David 9822

By looking into the results of this execution, you will understand that the execution of the query does not happen in one time; instead it defers the execution of the query until the actual data is requested. In our example the where user.Salary > 5000 line will execute only after the actual data is requested. Here it is the foreach statement when the data is requested. This property of LINQ is called deffered execution or deffered evaluation.

When you declare a query variable, it does not actually contain the result of the query,instead it captures the data structure of the query. This data structure contains the detail about what you want to query.

It is due to thiss feature of lazy initialization LINQ improves the performance of the queries. For example when you are querying a bulk data and want to stop the query after a particular condition is met, deffered execution helps you to improve the performance by not loading the results into the memory. It will only query the collection till the condition is met!!!.

Deffered execution is the default behaviour of LINQ queries. If you want to bypass the deffered execution, you have to call the .ToList() on the query like..

var userSalaries =

(from user in GetUsers()

where user.Salary > 5000

select new

{ Name = user.UserName, Salary = IncreaseSalary(user.Salary) }).ToList();

Will make my output look like

Increasing Salary...

Increasing Salary...

Increasing Salary...

Kemp Davis 8733

Rahul Bose 11000

Kim David 9822

Reason:

The normal query will iterate over the objects of type IEnumerable or IQueryable, .ToList() method converts my object into a IList type instead of a IQueryable type.

Tuesday, April 15, 2008

Enterprise Library 4.0 released

Those who keep a close look at the codeplex would have already noticed the release of the new Enterprise Library version (4.0) March CTP. The interesting news is that now you have a version which supports Visual Studio 2008 installation. (I was having a lot of problems configuring Enterprise Library 3.1 in my laptop which only had a Visual Studio 2008 installed).

Issues in the release:

The copyassemblies.bat file does not work!!!

Solution:

Refer to the post http://www.codeplex.com/entlib/WorkItem/View.aspx?WorkItemId=15938 in CodePlex with the fixed batch file.

Here is the summary of some interesting changes

  • Has the Allow Partially-Trusted Caller attribute (APTCA) on all assemblies. This means that you can call the methods of Enterprise Library and the application blocks from an application running in a partial trust environment.
  • You can replace the CacheManager class with the custom implementation if required. This does not affect the API of the application block or the existing CacheManager.
  • Implements new performance counters for Caching, Data, Exception and other application blocks.
  • Multiple ruleset support for Validation application block.
  • Policy injection block supports Validation Ruleset name and an order parameter for all the handlers which will specify the order of execution of the handlers.

Aspect Oriented Programing and Policy Injection Application Block (Part - 2)

As mentioned in Part 1 of this article series, The Policy Injection Application Block is used to seperate the core concerns of the entity by using handlers available in the block. You can also create your own custom handlers by implementing the ICallHandler interface.

PIAB can be used to specify crosscutting behavior of objects in terms of a set of policies. A policy is the combination of a series of handlers that execute when client code calls methods of the class and—with the exception of attribute-based policies—a series of matching rules that select the classes and class members (methods and properties) to which the application block attaches the handlers.

A handler can be defined either

• By decorating class members with an attribute that will declaratively define the handler to be used

OR

• By defining the class type and class member on which the handler will act

A common scenario when using any policy injection framework is the requirement to specify policies for classes and their members using attributes directly applied to the appropriate classes and members. The PIAB supports this technique; this means the only configuration required is the addition of the application block to the Enterprise Library configuration for the application. After that, the application block actively discovers classes and members with the attributes defined within the Policy Injection Application Block applied, and then the application block applies the appropriate policies.

Some of the common scenario where PIAB can be used in your application includes

  • Logging Method Invocation and Property Access
  • Handling Exceptions in a Structured Manner
  • Validating Parameter Values
  • Caching Method Results and Property Values
  • Authorizing Method and Property Requests
  • Measuring Target Method Performance

In the below given example I have used PIAB to handle exceptions, Caching and Validation purposes.

public class User : IUser

{

#region IUser Members

[ExceptionCallHandler("My Exception Policy")]

[CachingCallHandler]

public Collection<Int32> GetUserIDs()

{

return GetUserIDsFromDB();

}

private Collection<Int32> GetUserIDsFromDB()

{

Collection<Int32> ids = new Collection<Int32>();

ids.Add(1);

ids.Add(2);

System.Windows.Forms.MessageBox.Show("Getting ID's from DB");

return ids;

}

[ExceptionCallHandler("My Exception Policy")]

[ValidationCallHandler]

public void UpdateAge([RangeValidator(typeof(Int32), "20", RangeBoundaryType.Inclusive, "100", RangeBoundaryType.Exclusive)] Int32 age, Int32 index)

{

//Implementation code goes here

}

#endregion

}

After having the entity created with the appropriate handlers for avoiding cross concerns you can use the PIAB factory class methods for creating or obtaining object instances:
  • Create: This method creates a new instance of a policy-enabled interceptable target object.
  • Wrap: This method adds policies to existing interceptable target object instances.

IUser user = PolicyInjection.Create<User, IUser>();

And call the interface methods like

Collection<Int32> usersids = user.GetUserIDs();

The implementation of a system that automatically creates a proxy and handler pipelines for methods is similar to the aspect-oriented programming (AOP) approach. However, the Policy Injection Application Block is not an AOP framework implementation for the following reasons:
• It uses interception to enable only pre-processing handlers and post-processing handlers.
• It does not insert code into methods.
• It does not provide interception for class constructors.

Aspect Oriented Programing and Policy Injection Application Block (Part -1)

In Object Oriented programming classes and methods are designed for performing specific operations and common/duplicate functionality are factored out into common classes. However, there are cross-cutting concerns that span across all classes and methods, like logging, caching, exception handling, security etc.

The separation of concerns is a major consideration for any programming language. In the simplest terms, a concern is a modular unit of code that has a specific purpose. All programming methodologies, in some way or another, handle the separation of concerns by encapsulating them into some entity. In procedural languages, concerns are defined within procedures. In object-oriented languages, concerns are defined within classes. However, some concerns cannot be bound to these constructs.

For example, in my User class, I have used the exception handling code for the methods as given below.

public class User : IUser
{

#region IUser Members


public void Insert(IUser user)
{
try
{
//Implementation code goes here
}
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex,"My Exception Policy");
}
}

public void Remove(int index)
{
try
{
//Implementation code goes here
}
catch (Exception ex)
{
ExceptionPolicy.HandleException(ex, "My Exception Policy");
}
}

#endregion
}

During the process it was necessary for me to repeat the same code for Exception Handling in different functions. These types of cross-cutting concerns can be found in various regions of my code. Cross cutting concerns can occur in coding validation, caching etc also. Aspect oriented programming attempts to address these cross cutting concerns and eliminate repetitive and intermixing code in your application.

Aspect Oriented Programming model encapsulates these cross-cutting concerns using the following concepts

Join-points: The points in the structure of base-code where the cross-cutting functionality needs to execute. This can be method call, functions, properties etc.
Point-cut: A logical description of join-points using some specific syntax. Point-cut tells us when we should match a join point.
Advice: Decides the sequence of execution of advice code with respect to joint point. Additional code like exception, logging, validation and security check that each of these methods need to perform

Implementing Aspect Oriented Programming in .NET

In .NET, two approaches can be taken in aspect-oriented programming, Compile-time weaving, and Runtime weaving. Weaving is injecting instructions into the application.

Compile-time weaving happens at the compiler level and Code is injected into the source code of an application to address the cross-cutting concerns. Runtime weaving is done by using the .NET runtime. Instructions are injected at runtime, typically through the use of a proxy object that the consuming object sees as the original object. This behaves the same way as Remoting does.

There are lot of posts and blogs available for implementing AOP in C#. In this article series (Part 2) I will try to explain how the Policy Injection Application Block (PIAB) can be used to separate the core concerns of the entity, such as business logic, from the cross-cutting concerns (Exception, Logging etc) that are required to develop an application.

Friday, April 11, 2008

Enterprise Library 3.1 – Validation Application Block

Any application that accepts input either from users or from other systems must ensure that the information is valid in terms of some set of rules that you specify. The Validation Application Block provides the functionality necessary to validate .NET Framework data types. The data type validation is performed by a series of classes called validators.

The Validation Application Block is designed to address the most common tasks developers face when they must validate input either from a user or another system. These tasks are arranged according to scenarios. Each scenario gives an example of a typical way to use the Validation Application Block and shows the code that accomplishes the task.

The scenarios are the following:

• Using attributes to define validation rules
• Using configuration to define validation rules
• Validating objects
• Using self validation to define validation rules within your classes

Integrating the Validation Application Block into the following types of applications:

• ASP.NET
• Windows Forms
• WCF

Validator Class
The core component of the Validation Application Block is the Validator class. This class is the base class from which all validators inherit. The Validator class contains an overloaded method called Validate. The purpose of the Validate method is to validate a given object and determine whether or not it passes validation based on the rules of the validator.

public abstract class Validator<T> : Validator
{
protected Validator(string messageTemplate, string tag);

protected internal override void DoValidate(object objectToValidate, object currentTarget, string key, ValidationResults validationResults);
protected abstract void DoValidate(T objectToValidate, object currentTarget, string key, ValidationResults validationResults);

public ValidationResults Validate(T target);

public void Validate(T target, ValidationResults validationResults);
}


ValidationResults Class
The ValidationResult class represents specific results returned by a Validator instance. When a Validator instance determines that a rule is violated, a new instance of ValidationResult is created and added to the ValidationResults collection. The ValidationResults class provides a collection of validation results that were processed during the validation of an object. If validation results were returned, then one or more rules were broken during the validation process.

[Serializable]
public class ValidationResults : IEnumerable<ValidationResult>, IEnumerable
{
public ValidationResults();

public bool IsValid { get; }
public void AddAllResults(IEnumerable<ValidationResult> sourceValidationResults);
public void AddResult(ValidationResult validationResult);
public ValidationResults FindAll(TagFilter tagFilter, params string[] tags);
}


The ISValid Property returns True if the count of ValidataionResult instances in the collection is 0. Otherwise it returns False. We can find whether the validation is passed or not by checking the IsValid property of the ValidationResults class.

ValidationFactory Class
This class is responsible for creating a specific Validator class instance.

public static class ValidationFactory
{

public static Validator<T> CreateValidator<T>();
public static Validator<T> CreateValidator<T>(IConfigurationSource configurationSource);
public static Validator<T> CreateValidator<T>(string ruleset);
public static Validator CreateValidator(Type targetType);
public static Validator<T> CreateValidator<T>(string ruleset, IConfigurationSource configurationSource);
public static Validator CreateValidator(Type targetType, string ruleset);
public static Validator CreateValidator(Type targetType, string ruleset, IConfigurationSource configurationSource);
public static Validator<T>CreateValidatorFromAttributes<T>();
public static Validator<T> CreateValidatorFromAttributes<T>(string ruleset);
public static Validator CreateValidatorFromAttributes(Type targetType, string ruleset);
public static Validator<T> CreateValidatorFromConfiguration<T>();
public static Validator<T>CreateValidatorFromConfiguration<T>(IConfigurationSource configurationSource);
public static Validator<T> CreateValidatorFromConfiguration<T>(string ruleset);
public static Validator<T> CreateValidatorFromConfiguration<T>(string ruleset, IConfigurationSource configurationSource);
public static Validator CreateValidatorFromConfiguration(Type targetType, string ruleset);
public static Validator CreateValidatorFromConfiguration(Type targetType, string ruleset, IConfigurationSource configurationSource);
public static void ResetCaches();
}


The three overloaded methods, CreateValidator<T>, CreateValidatorFromConfiguration<T>, CreateValidatorFromAttributes<T> creates the validator instances based on the request.

Creating an Instance of the Validator Class via the ValidationFactory Class
For incorporating Validation Application Block in .NET application we need to add references to the following assemblies

• Microsoft.Practices.EnterpriseLibrary.Validation
• Microsoft.Practices.EnterpriseLibrary.Validation.Validators
• Microsoft.Practices.EnterpriseLibrary.Common.dll

If you are using the ASP.NET, Windows Forms, or WCF integration assemblies, add one of the following references as appropriate.

• Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms.dll
• Microsoft.Practices.EnterpriseLibrary.Validation.Integration.AspNet.dll
• Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WCF.dll

Validation application block comes with three main categories of validators. Object validators, Composite validators and Basic validators.


public class Employee
{
[ValidatorComposition(CompositionType.And)]
[StringLengthValidator(1, 50, Ruleset = "RuleSetA", MessageTemplate = "First Name must be between 1 and 50 characters")]
[NotNullValidator( MessageTemplate="Name cannot be null", Ruleset="RuleSetA")]
public String Name { get; set; }

[RangeValidator(20, RangeBoundaryType.Inclusive, 55, RangeBoundaryType.Inclusive, Ruleset="RuleSetA", MessageTemplate= "Age must be between 20 and 55")]
public Int32 Age { get; set; }

[RegexValidator(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", MessageTemplate="Invalid e-mail address", Ruleset = "RuleSetA")]
public String Email { get; set; }

[RangeValidator(2000D, RangeBoundaryType.Exclusive, 0D, RangeBoundaryType.Ignore, Ruleset="RuleSetA", MessageTemplate="Salary should be minimum 2000")]
public Double Salary { get; set; }

[DateTimeRangeValidator("1978-01-01T00:00:00", "2008-01-01T00:00:00", MessageTemplate="Joining date should be between 01-01-1978 and 01-01-2008", Ruleset="RuleSetA")]
public DateTime DOJ { get; set; }
}


The above code sample defines a class Employee that includes a number of properties such as Name, Age, Salary, DOJ (Date of Joining), Email. Attributes that are attached to these properties associate them with validators. For example, the StringLengthValidator, NotNullValidator, ValidatorComposition attribute is attached to the Name property and associates it with the respective StringLengthValidator, NotNullValidator, ValidatorComposition class. Each validator has an additional NamedParameter set like MessageTemplate and RuleSet that defines the message template to show when the validation is failed and the rule set to valdiate respectively.
The Ruleset parameter of the validation attributes indicates that the application block will use "RuleSetA" rather than the anonymous, default rule set.
Once you have the validators and rule sets, you can validate your objects. The easiest way to do this is to use the Validation facade. The facade is responsible for creating the validator instance to validate the objects.

Employee emp = new Employee
{
Name = "Brian Williams”,
Age = 34,
DOJ = Convert.ToDateTime("07/07/2000"),
Email = "brian.williams@someserver.com",
Salary = 9990D
};
Validator<Employee> validator = ValidationFactory.CreateValidator<Employee>("RuleSetA");
ValidationResults results = validator.Validate(emp);

if (results.IsValid)
MessageBox.Show("Valid");
else
MessageBox.Show("Not Valid");

Tuesday, April 1, 2008

DoNotExposeGenericLists error and Using Collection<T> instead of List<T>

If you have ever exposed a List<T> from a method / Property in a .NET assembly code, while running FxCop you are supposed to get the ‘DoNotExposeGenericLists’ error as follow.

Do not expose List<T> in object models. Use Collection<T>, ReadOnlyCollection<T> or KeyedCollection instead. List<T> is meant to be used from implementation, not in object model API. List<T> is optimized for performance at the cost of long term versioning. For example, if you return List<T> to the client code, you will not ever be able to receive notifications when client code modifies the collection.

Reason:

· List<T> is not designed for extensibility. It does not support members that can be overridden. An object returning a List<T> won’t be able to get notified when the collection is changed.
· List<T> is intended to be a class used in internal implementation. By exposing a List<T> in the interface of your class, you are breaking encapsulation by giving client code access to an implementation detail of your class--especially if your property provides direct access to the internal List<T> .
· Collection<T> is designed for extensibility and helps you to notify changes in the collection by overriding the methods exposed by the Collection<T>

David Kean from MS Code Analysis team has a very good article explaining the rule. I will try to use Dave’s example to explain the advantages of using Collection<T> over List<T> while exposing the type for public API.

The following example shows how to derive a collection class from a constructed type of Collection<T> generic class, and how to override the InsertItem, ClearItem, SetItem and RemoveItem to provide notification about the collection changes.


public class Person
{
private AddressCollection _addresses;

public Collection<Address> Addresses
{
get
{
if (_addresses == null)
_addresses = new AddressCollection(this);
return _addresses;
}
}

public event EventHandler<addresschangedeventargs> AddressChanged;

protected virtual void OnAddressInserted(Address item)
{
EventHandler<addresschangedeventargs> temp = AddressChanged;

if (temp != null)
temp(this, new AddressChangedEventArgs(ChangeType.Added, item.Country, null));
}

private void RaiseAddressInserted(Address item)
{
OnAddressInserted(item);
}



private class AddressCollection : Collection<address>
{
private Person _owner;

public AddressCollection(Person _person)
{
_owner = _person;
}


protected override void InsertItem(int index, Address item)
{
base.InsertItem(index, item);
_owner.RaiseAddressInserted(item);
}

}
}



From the above code you can see how to get notified by exposing the Collection<T> when changes occur in the collection. Similarly you can implement the RemoveItem, ClearItem and SetItem methods and raise events that notify the respective changes.


You can also encapsulate the List<T> and expose the methods that are relevant to the application by calling the underlying List<T> implementation. I will show how to expose the Find(), Sort() and FindAll() methods of List<T> while using Collection<T>

For example I have made some changes to the AddressCollection class for exposing the List<T> methods


private class AddressCollection : Collection<Address>
{
private Person _owner;
public AddressCollection(Person _person) : base(new List<Address>())
{
_owner = _person;
}


. . . .
. . . .

protected internal Address Find(Predicate<Address> match)
{
List<Address> items = (List<Address> )Items;
return items.Find(match);
}

protected internal void Sort(Comparison<Address> match)
{
List<Address> items = (List<Address> )Items;
items.Sort(match);
}

protected internal IEnumerable<Address> FindAll(Predicate<Address> match)
{
List<Address> items = (List<Address> )Items;
return (IEnumerable<Address> )items.FindAll(match);
}
}



Later in your Person class you can have the methods to get the desired functionality


public Address FindAddressByStreet(String street)
{
return _addresses.Find(delegate(Address a)
{
return a.Street.StartsWith(street);
});
}


public IEnumerable<Address> FindAllAddressByState(String state)
{
return _addresses.FindAll(delegate(Address a)
{
return a.State == state;
});
}


public void SortAddressByState()
{
_addresses.Sort(delegate(Address a1, Address a2)
{
return a1.State.CompareTo(a2.State);
});
}