Search This Blog

Wednesday, November 16, 2011

Difference between const, static and readonly in c#

Within a class, const, static and readonly members are special in comparison to the other modifiers.


const vs. readonly

const and readonly perform a similar function on data members, but they have a few important differences.



const

A constant member is defined at compile time and cannot be changed at runtime. Constants are declared as a field, using the const keyword and must be initialized as they are declared. For example;

public class MyClass
{
  public const double PI = 3.14159;
}
 
PI cannot be changed in the application anywhere else in the code as this will cause a compiler error.
Constants must be a value type (sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool), an enumeration, a string literal, or a reference to null.

Since classes or structures are initialized at run time with the new keyword, and not at compile time, you can't set a constant to a class or structure.

Constants can be marked as public, private, protected, internal, or protected internal.
Constants are accessed as if they were static fields, although they cannot use the static keyword.
To use a constant outside of the class that it is declared in, you must fully qualify it using the class name.


readonly

A read only member is like a constant in that it represents an unchanging value. The difference is that a readonly member can be initialized at runtime, in a constructor as well being able to be initialized as they are declared. For example:

public class MyClass
{
  public readonly double PI = 3.14159;
}
or
public class MyClass
{
  public readonly double PI;
 
  public MyClass()
  {
    PI = 3.14159;
  }
}
 
Because a readonly field can be initialized either at the declaration or in a constructor, readonly fields can have different values depending on the constructor used. A readonly field can also be used for runtime constants as in the following example:

public static readonly uint l1 = (uint)DateTime.Now.Ticks;
 
Notes
  • readonly members are not implicitly static, and therefore the static keyword can be applied to a readonly field explicitly if required.
  • A readonly member can hold a complex object by using the new keyword at initialization.


static

Use of the static modifier to declare a static member, means that the member is no longer tied to a specific object. This means that the member can be accessed without creating an instance of the class. Only one copy of static fields and events exists, and static methods and properties can only access static fields and static events. For example:

public class Car
{
  public static int NumberOfWheels = 4;
}
 
The static modifier can be used with classes, fields, methods, properties, operators, events and constructors, but cannot be used with indexers, destructors, or types other than classes.
static members are initialized before the static member is accessed for the first time, and before the static constructor, if any is called. To access a static class member, use the name of the class instead of a variable name to specify the location of the member. For example:

int i = Car.NumberOfWheels;

Exposing 2 endpoints for same WCF service using different Bindings



I just created a simple which exposes a service through 2 different endpoints which uses different bindings.One is basicHttpBinding and another using wsHttpBinding.

Specifying 2 EndPoints 

If you have a basic idea about WCF you can easily understand the below configuration in web.config which exposes  Uploader service through 2 different end points.

<services>
 
<service behaviorConfiguration="DemoMTOM.Web.UploaderBehavior"  name="DemoMTOM.Web.Uploader">
   
<endpoint address="bh" binding="basicHttpBinding" contract="DemoMTOM.Web.IUploader">
     
<identity>
       
<dns value="localhost"/>
     
</identity>
   
</endpoint>
   
<endpoint address="wh" binding="wsHttpBinding" contract="DemoMTOM.Web.IUploader">
     
<identity>
       
<dns value="localhost"/>
     
</identity>
   
</endpoint>
   
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
 
</service>
</services>

In the sample the url to the basicHttpBinding endpoint is http://localhost:64738/Uploader.svc/bh and the url to the wsHttpBinding endpoint is http://localhost:64738/Uploader.svc/wh. You can check this by adding a service reference in to a WPF application. 

Creating ServiceClient to call the service in WPF
When we create service reference in the WPF application, the app.config in the WPF application will get 2 entries.One for basicHttpBinding and another for wsHttpBinding.See the sample app.config below.


<client>
   
<endpoint address="http://localhost:64738/Uploader.svc/bh" binding="basicHttpBinding"
       
bindingConfiguration="BasicHttpBinding_IUploader" contract="UploadServiceReference.IUploader"
       
name="BasicHttpBinding_IUploader" />
   
<endpoint address="http://localhost:64738/Uploader.svc/wh" binding="wsHttpBinding"
       
bindingConfiguration="WSHttpBinding_IUploader" contract="UploadServiceReference.IUploader"
       
name="WSHttpBinding_IUploader">
       
<identity>
           
<dns value="localhost" />
       
</identity>
   
</endpoint>
</client>


So at the calling side there will be confusion of course in selecting the end point.So to resolve that confusion we have to specify the endPointConfigurationName at the time of creating client. See code below which uses the basicHttpBinding.


UploadServiceReference.UploaderClient cli = new UploadServiceReference.UploaderClient("BasicHttpBinding_IUploader");
string res = cli.DoWork("Joy");



UploadServiceReference.UploaderClient cli = new UploadServiceReference.UploaderClient("WSHttpBinding_IUploader");
string res = cli.DoWork("Joy");

The second code snippet uses wsHttpBinding to call the service.

Hosting service using 2 endpoints in a Console Application


static void Main(string[] args)
{
   
try
    {
        ServiceHost serviceHost =
new ServiceHost(typeof(Uploader),
           
new Uri("http://localhost:64738/Uploader.svc"));

        serviceHost.AddServiceEndpoint(
typeof(IUploader), new BasicHttpBinding(), "bh");
        serviceHost.AddServiceEndpoint(
typeof(IUploader), new WSHttpBinding(), "wh");

        ServiceMetadataBehavior smb =
new ServiceMetadataBehavior();
        smb.HttpGetEnabled =
true;
        serviceHost.Description.Behaviors.Add(smb);

        ServiceDebugBehavior sdb =  serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
        sdb.IncludeExceptionDetailInFaults =
true;

        serviceHost.Open();

        Console.WriteLine(
"Service running below are the Endpoints :");
       
foreach (ServiceEndpoint se in serviceHost.Description.Endpoints)
        {
            Console.WriteLine(se.Address.ToString());
        }
        Console.WriteLine(
"Press any key to quit...");
        Console.ReadLine();

        serviceHost.Close();
    }
   
catch (Exception ex)
    {
        Console.WriteLine(
string.Format("Error :{0}", ex.Message));
        Console.ReadLine();
    }
}

In the sample when you try to run the console application it will throw an error because the asp.net application also runs and uses the same port. So run the console application from command line or explorer.

There is no need to change the reference in the WPF application since both these console application and asp.net service host is using same url.


Popular Posts