a DotNetStyling - .Net World by Armen Ayvazyan
Welcome to DotNetStyling Sign in | Join | Help
Add to Technorati Favorites Add to Google Reader or Homepage Add to My AOL Subscribe in FeedLounge Subscribe in Bloglines Add to Excite MIX Add to flurry Add to Pageflakes Subscribe in NewsGator Online


C# 3.0 Features. Part V: Partial Methods

The new interesting feature of C# 3.0 is Partial Methods. Basically the name “Partial” is not accurate to this feature. First what comes to the head is an idea that method is implemented in separated place like “Partial” classes but this is actually not true.

Looks like a “virtual”

Partial methods gives ability to specify the usage of method in one class and keep implementation in other class. It is similar to well known “virtual” methods but with a bit difference and restrictions.

Example:

   1: partial class User
   2: {
   3:     public int UserId{get; set;}
   4:     
   5:     private string _userName;
   6:     public string UserName
   7:     {
   8:         get
   9:         {
  10:             return _userName;
  11:         }
  12:         set
  13:         {
  14:             BeforeSettingUsername();
  15:             _userName = value;
  16:             AfterSettingUsername();
  17:         }
  18:     }
  19:  
  20:     partial void BeforeSettingUsername();
  21:     partial void AfterSettingUsername();
  22: }
  23:  
  24: partial class User
  25: {
  26:     partial void BeforeSettingUsername()
  27:     {
  28:         Console.WriteLine("Make operation before setting user name");
  29:     }
  30:  
  31:     partial void AfterSettingUsername()
  32:     {
  33:         Console.WriteLine("Make operation after setting user name");
  34:     }
  35: }

In this example there are two partial methods (BeforeSettingUsername() and AfterSettingUsername()) defined and used in first class but the actual implementation is in another class. After setting value to Username property the implementation inside of partial methods will be executed:

   1: static void Main(string[] args)
   2: {
   3:     User user = new User();
   4:  
   5:     user.UserName = "DotNetStyling";
   6:     
   7:     Console.ReadKey();
   8: }
image

As you can see method looks similar to virtual method implementation. The main difference is that compiler ignores Partial Methods without implementation. In IL code there will be no sign of that method. Only partial methods with implementation will be compiled.

For instance let’s add one more partial method (PartialMethodWithotImplementation) which won’t have any implementation:

   1: partial class User
   2: {
   3:     public int UserId{get; set;}
   4:     
   5:     private string _userName;
   6:     public string UserName
   7:     {
   8:         get
   9:         {
  10:             return _userName;
  11:         }
  12:         set
  13:         {
  14:             BeforeSettingUsername();
  15:             _userName = value;
  16:             AfterSettingUsername();
  17:  
  18:             PartialMethodWithotImplementation();
  19:         }
  20:     }
  21:  
  22:     partial void BeforeSettingUsername();
  23:     partial void AfterSettingUsername();
  24:     partial void PartialMethodWithotImplementation();
  25: }

Now, if we compile application, run ILDasm and explore our User class then we’ll find that there is no sign of PartialMethodWithoutImplementation method. Unlike AfterSettingUsername and BeforeSettingUsername the PartialMethodWithoutImplementation was not compiled because it doesn’t have any implementation:

image

Partial methods were mainly created to support “LINQ to SQL” where main class with all entities generated with usage of partial methods.

I generated one simple DataContext file for illustration:

   1: [Table(Name="dbo.cs_Posts")]
   2: public partial class cs_Post : INotifyPropertyChanging, INotifyPropertyChanged
   3: {
   4:     
   5:     private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
   6:     
   7:     private int _PostID;
   8:     
   9: #region Extensibility Method Definitions
  10: partial void OnLoaded();
  11: partial void OnValidate(System.Data.Linq.ChangeAction action);
  12: partial void OnCreated();
  13: partial void OnPostIDChanging(int value);
  14: partial void OnPostIDChanged();
  15: partial void OnPostAuthorChanging(string value);
  16: partial void OnPostAuthorChanged();
  17: partial void OnSubjectChanging(string value);
  18: partial void OnSubjectChanged();
  19: partial void OnPostDateChanging(System.DateTime value);
  20: partial void OnPostDateChanged();
  21: partial void OnBodyChanging(string value);
  22: partial void OnBodyChanged();
  23: #endregion
  24:     
  25:     public cs_Post()
  26:     {
  27:         OnCreated();
  28:     }
  29:     
  30:     [Column(Storage="_PostID", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
  31:     public int PostID
  32:     {
  33:         get
  34:         {
  35:             return this._PostID;
  36:         }
  37:         set
  38:         {
  39:             if ((this._PostID != value))
  40:             {
  41:                 this.OnPostIDChanging(value);
  42:                 this.SendPropertyChanging();
  43:                 this._PostID = value;
  44:                 this.SendPropertyChanged("PostID");
  45:                 this.OnPostIDChanged();
  46:             }
  47:         }
  48:     }
  49: }

As you can see “LINQ to SQL” template will generates for us bunch of partial methods (OnLoaded(), OnValidate(), etc) which used inside of PostID property. If there won’t be any implementation of those methods then compiler will simply ignore their’s existence.

 

Rules

There are several rules applies to Partial Methods:

  • Partial methods should be defined and implemented only in Partial Classes
  • Method should specify the partial modifier
  • Partial methods are private but private access modifies must not be specified
  • Return type of partial method should be void
  • No need to implement partial methods if you don’t need them
  • Partial method can be static
  • It can accept arguments like other “standard” methods.

 

If you experience of using partial classes then partial methods could be useful feature for you. 

 

Previous materials of C# 3.0 Feature series:

 

Technorati tags: , ,
C# 3.0 Features. Part IV: Anonymous Types

 

Previous materials of C# 3.0 Feature series:

"Dynamic" Classes

Anonymous Type is basically the C# way how we can dynamically create, populate and use a class without type declaration. If for some reason we need temporary classes as data carrier without any business logic implementation then Anonymous Types could be the perfect solution. Instead of having statically declared bunch of standard classes we can eliminate our efforts and use Anonymous types. Actually this feature mainly was created to support Expression Tree and LINQ which would be hard to implement without it.

Anonymous type declaration syntax is very simple.

   1: var someObject = new {Name = "Bob", Age = 23};

As you can see we used three technics introduced by C# 3.0 features: Auto Property, new Object initialization syntax and var keyword. Without any of them it won’t be possible to have Anonymous Types in game.

  

How does it work?

Actually Anonymous Type is not such “anonymous” like it sounds. What actually happens is that during the compilation compiler creates “static” type for us.

If we compile the application and look at the compiled IL code then we will find some strange f_AnonymousType0’2 class.

image

This is our Anonymous Type introduced by compiler which actually under the hood creates type with public properties.

image

  

Usage

After declaration of object based on Anonymous Type we are free to use it in a standard way as we do with standard classes including intellisense support.

image

   1: var someObject = new {Name = "Bob", Age = 23};
   2: Console.WriteLine("Name is {0}, age is {1}", someObject.Name, someObject.Age);

image

 

C# 3.0 Features. Part III: The var keyword

Previous materials of C# 3.0 Feature series:

 

“var” keyword

During the local variable declaration we have to explicitly specify the type even if the variable doesn’t have any value yet. The “var” expression brings as ability do not specify the type during local variable declaration. The compiler will get it from the initializer.

Let’s declare two local variables of the same type (User) but one will be declared in standard (old) way and another one with using “var” keyword.

   1: User userTodd = new User() { UserName = "Todd" };
   2:  
   3: var userBob = new User() {UserName = "Bob"};

Disassembler shows that both variables (userTodd and userBob) have the same type CSharp30Features.User even we did not explicitly specify the type in case of userBob variable.

image

Also keep in mind that ones the variable has been initialized by one type it won’t be possible to reassign it to another type. We will get compile time error:

   1: var someVar = 1;
   2: someVar = "This assignment will bring compile time error";

 

Why to use “var” keyword?

The obvious question is what is the advantage of using “var” keyword. 

Redundancy in expression

We do not need to specify type twice in local variable declaration expression.

   1: SomeType varName = new SomeType();

The right side of the expression already shows which type variable will be. It is enough to specify it just ones:

   1: var varName = new SomeType();

Anonymous Types support.

“var” expression became necessarily after introducing the Anonymous Types. In case of Anonymous Type declaration we cannot use standard expression as the type which variable has to be assign to is unknown.

   1: ??? someVar = new {Property1="value", Property2="Another value"};

This is a valid expression for Anonymous Types:

   1: var someVar = new {Property1="value", Property2="Another value"};

I am planning to speak explicitly about Anonymous Types in my next upcoming blog post “C# 3.0 Features. Part IV: Anonymous Types”

Technorati tags: , ,
C# 3.0 Features. Part II: Object and Collection Initialization

Previous materials of C# 3.0 Feature series:

Object Initialization

New object initialization technique gives us ability to define and fill the public property of the object on the fly. This expression was created to support LINQ but it can be used anywhere. This expression helps to fill values during the initialization and keep constructor empty.

   1: public enum Sex { Male, Female }
   2:  
   3: public class User
   4: {
   5:     public int UserId { get; private set; }
   6:     public string UserName { get; set; }
   7:     public string UserAddress { get; set; }
   8:     public DateTime DateOfBirth { get; set; }
   9:     public Sex UserSex { get; set; }
  10: }

User object initialization by using OLD style expression:

   1: User user = new User();
   2: user.UserAddress = "FR, Paris";
   3: user.DateOfBirth = new DateTime(1984, 1, 1);
   4: user.UserName = "Michelle";
   5: user.UserSex = Sex.Female;

Similar object initialization by using new feature:

   1: User user = new User
   2:                 {
   3:                     UserAddress = "US,Redmond",
   4:                     DateOfBirth = new DateTime(1974, 1, 1),
   5:                     UserName = "Mike",
   6:                     UserSex = Sex.Male
   7:                 };

Collection Initialization

There is a similar feature for collection initialization. We can define a collection and add object on the fly.

The standard way of collection initialization:

   1: List<User> users = new List<User>();
   2: users.Add(user1);
   3: users.Add(user2);

Initialization of collection by using new C# 3.0 feature:

   1: List<User> users = new List<User>{user1, user2};

Both in one

Finally we can combine those two expressions and have the whole collection initialization in one line. This could be helpful when preparing collection with dummy data for testing.

   1: List<User> users = new List<User>
   2:                                 {
   3:                                     new User
   4:                                         {
   5:                                             UserAddress = "US,Redmond",
   6:                                             DateOfBirth = new DateTime(1974, 1, 1),
   7:                                             UserName = "Mike",
   8:                                             UserSex = Sex.Male
   9:                                         },
  10:                                     new User
  11:                                         {
  12:                                             UserAddress = "US, New-York",
  13:                                             DateOfBirth = new DateTime(1978, 1, 1),
  14:                                             UserName = "David",
  15:                                             UserSex = Sex.Male
  16:                                         }
  17:                                 };

 

 

Share this post :