Wednesday, April 30, 2008

Partial Classes-2

The first example shows an easy solution todefining nested types. With the power ofpartial classes, nested types can be completely isolated to their ownfiles. DataAccessLayer is defined as partial sothat the nested type DataSourceCollection can be defined in a separatepart. The second example is probably more of atelling of the dangers of partial types when used for no good reason. Here we see that both the containing typeDataAccessLayer and the contained type DataSourceCollection are defined aspartial. Hence the the definitions can bebroken into multiple parts. Please practicecaution when using partial types, particularly with regard to nested types. You will find that in a complex program it will bealmost impossible to determine what the full definition of any one type is onceit is defined as partial.

Partialtype attributes
Attributes on partial types are combined in anunspecified order so that the appear to all be defined on the given type. In the preceding section we defined a typeDataAccessLayer as follows.

public partial class DataAccessLayer
{
DataSourceCollection sources;
publicDataAccessLayer()
{
sources =new DataSourceCollection();
}

publicDataSourceCollection DataSources
{
get
{
return sources;
}
}

}

public partial classDataAccessLayer
{
public classDataSourceCollection
{
Hashtableitems;
publicDataSourceCollection()
{
items = new Hashtable();
}

publicDataSource this[string dataSourceName]
{
get
{
return(DataSource)items[dataSourceName];
}
}
}
}


Attributes can be added to each part of the typedefinition as follows.

//Dal.cs
[Docking]
public partial classDataAccessLayer
{
DataSourceCollection sources;
publicDataAccessLayer()
{
sources =new DataSourceCollection();
}

publicDataSourceCollection DataSources
{
get
{
return sources;
}
}
}

//dal.datasourcecollection.cs
[Serializable]
public partial classDataAccessLayer
{
public classDataSourceCollection
{
Hashtableitems;
publicDataSourceCollection()
{
items = new Hashtable();
}
publicDataSource this[string dataSourceName]
{
get
{
return(DataSource)items[dataSourceName];
}
}

}
}

In the above example, an different attribute hasbeen added to each part of the definition of DataAccessLayer. To the part defined in dal.cs, the attributeDockingAttribute has been attached. To the partdefined in dal.datasourcecollection.cs, the SerializableAttribute has beenattached. This activity is equivalent tospecifying both attributes on the type asfollows.

[Serializable, Docking ]

Inheritanceand Interface Implementation
Now that we are done having all this fun it’s timeto lay down some rules regarding what you can and cant do with partialtypes. To help with the discussion, it isimportant that we visualize what the end result of a partial type is. The previous section defined a partial typeDataAccessLayer as follows.

//Dal.cs
[Docking]
public partial classDataAccessLayer
{
DataSourceCollection sources;
publicDataAccessLayer()
{
sources =new DataSourceCollection();
}

publicDataSourceCollection DataSources
{
get
{
return sources;
}
}
}

//dal.datasourcecollection.cs
[Serializable]
public partial classDataAccessLayer
{
public classDataSourceCollection
{
Hashtableitems;
publicDataSourceCollection()
{
items = new Hashtable();
}
publicDataSource this[string dataSourceName]
{
get
{
return(DataSource)items[dataSourceName];
}
}

}
}

This definition, once compiled, will be equivalentto the listing below.

[Docking, Serializable]
public classDataAccessLayer
{
DataSourceCollection sources;
publicDataAccessLayer()
{
sources =new DataSourceCollection();
}

publicDataSourceCollection DataSources
{
get
{
return sources;
}
}

public class DataSourceCollection
{
Hashtableitems;
publicDataSourceCollection()
{
items = new Hashtable();
}
publicDataSource this[string dataSourceName]
{
get
{
return(DataSource)items[dataSourceName];
}
}

}
}


The lesson here is that a partial class, no matterhow fragmented, is still on functional unit. Hence, any accessibility specifications applied to a partial type must agreewith all parts of the type that also include the accessibilityspecification. The concept is illustrated withthe sample below.

[Docking]
public partial classDataAccessLayer : GenericDAL
{
DataSourceCollection sources;
publicDataAccessLayer()
{
sources =new DataSourceCollection();
}

publicDataSourceCollection DataSources
{
get
{
return sources;
}
}
}


internal partialclass DataAccessLayer : GenericDAL
{
public classDataSourceCollection
{
Hashtableitems;
publicDataSourceCollection()
{
items = new Hashtable();
}
publicDataSource this[string dataSourceName]
{
get
{
return(DataSource)items[dataSourceName];
}
}

}
}

Notice that in this definition of DataAccessLayer,the two parts inherit from a base type GenericDAL. Also notice that while one part defines the class aspublic, the other uses the internal modifier. Attempting to compile this listing will fail with the followingmessage.

Error1 Partial declarations of'PartialTypes2.DataAccessLayer' have conflicting accessibilitymodifiers

The reason is evident from our first demonstrationin this section. Although DataAccessLayer isfragmented, it is still type and a type cannot be both internal and public atthe same time.

The next issue is that of base classes, andis not as easy to ascertain. Examine the listing below.

[Docking]
public partial classDataAccessLayer : GenericDAL
{
DataSourceCollection sources;
publicDataAccessLayer()
{
sources =new DataSourceCollection();
}

publicDataSourceCollection DataSources
{
get
{
return sources;
}
}
}


partial classDataAccessLayer : DataSource
{
public classDataSourceCollection
{
Hashtableitems;
publicDataSourceCollection()
{
items = new Hashtable();
}
publicDataSource this[string dataSourceName]
{
get
{
return(DataSource)items[dataSourceName];
}
}

}
}

Although the modifier incompatibility has beenremoved from the type, a problem persists during compilation of the abovesource. The difference here is that the secondpart of DataAccessLayer is now attempting to inherit from a different base typeDataSource, than the first part which inherits from GenericDAL. This might not seem intuitive because it contradictsthe combining behavior of partial type attributes; however, returning to ourinitial demonstration on the singularity of partial types, DataAccessLayer is atype; consequently, it can only inherit from one base class. The formal rule dictates that when a partial classdeclaration includes a base class specification it must agree with all otherparts that include a base class specification. Attempting to compile the listing above would produce the following errormessage.

Error1 Partial declarations of'PartialTypes2.DataAccessLayer' must not specify different base classes

Now in the world of interfaces, where multipleinheritance is the game, the compining behavior returns. Examine the example below.

public partial class DataAccessLayer : GenericDAL
{
DataSourceCollection sources;
publicDataAccessLayer()
{
sources =new DataSourceCollection();
}

}


partial classDataAccessLayer : IDataSourceManager
{
publicDataSourceCollection DataSources
{
get
{
return sources;
}
}

public classDataSourceCollection
{
Hashtableitems;
publicDataSourceCollection()
{
items = new Hashtable();
}
publicDataSource this[string dataSourceName]
{
get
{
return(DataSource)items[dataSourceName];
}
}

}
}
Similar to the example in the last section, thesecond part of DataAccessLayer defines a different base than the first. Unlike the sample in the previous section; however,IDataSourceManager is an interface and not a class. The formal rule state that the set of baseinterfaces for a type declared in multiple parts is the union of the baseinterfaces specified on each part. Furthermore,a particular base interface may only be named once on each part, but it ispermitted for multiple parts to name the same base interface(s).

This means that the first part in the listingabove could have been defined to include the IDataSourceManager interface aswell. The listing below illustrates.


public partial class DataAccessLayer : GenericDAL,IDataSourceManager
{
DataSourceCollection sources;
publicDataAccessLayer()
{
sources =new DataSourceCollection();
}

}

<<<<Previous

No comments: