Click here to Skip to main content
15,880,469 members
Articles / Programming Languages / C#

Performance implications of Exceptions in .NET

Rate me:
Please Sign up or sign in to vote.
4.45/5 (66 votes)
9 Aug 2005CPOL7 min read 219.1K   976   105  
Presentation and analysis of performance costs when throwing exceptions in .NET.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Timers;
using System.Data.SqlClient;
using System.Reflection;
using System.Security.Policy;

namespace ExceptionPerformance
{
	/// <summary>
	/// Summary description for MainForm.
	/// </summary>
	public class MainForm : System.Windows.Forms.Form
	{
		private System.Windows.Forms.GroupBox groupBox1;
		private System.Windows.Forms.RadioButton radioNoException;
		private System.Windows.Forms.RadioButton radioThrow;
		private System.Windows.Forms.RadioButton radioRethrow;
		private System.Windows.Forms.GroupBox groupBox2;
		private System.Windows.Forms.RadioButton radioEmpty;
		private System.Windows.Forms.RadioButton radioString;
		private System.Windows.Forms.RadioButton radioFile;
		private System.Windows.Forms.RadioButton radioDatabase;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.TextBox textTime;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.Label label3;
		private System.Windows.Forms.Button buttonRun;
		private System.Windows.Forms.RadioButton radioCatch;
		private System.Windows.Forms.TextBox textResultM;
		private System.Windows.Forms.TextBox textResultT;
		private System.Windows.Forms.TextBox textAverageT;
		private System.Windows.Forms.Label label5;
		private System.Windows.Forms.TextBox textAverageM;
		private System.Windows.Forms.TextBox textResultR;
		private System.Windows.Forms.TextBox textAverageR;
		private System.Windows.Forms.CheckBox checkDomain;
		private System.Windows.Forms.Button buttonClear;
		private System.Windows.Forms.RadioButton radioRethrowNew;
		private System.Windows.Forms.RadioButton radioComplex;
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public MainForm()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();
			InitAppDomain();

			this.radioNoException.Checked = true;
			this.radioEmpty.Checked = true;
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.groupBox1 = new System.Windows.Forms.GroupBox();
			this.radioCatch = new System.Windows.Forms.RadioButton();
			this.radioRethrow = new System.Windows.Forms.RadioButton();
			this.radioThrow = new System.Windows.Forms.RadioButton();
			this.radioNoException = new System.Windows.Forms.RadioButton();
			this.groupBox2 = new System.Windows.Forms.GroupBox();
			this.radioDatabase = new System.Windows.Forms.RadioButton();
			this.radioFile = new System.Windows.Forms.RadioButton();
			this.radioString = new System.Windows.Forms.RadioButton();
			this.radioEmpty = new System.Windows.Forms.RadioButton();
			this.label1 = new System.Windows.Forms.Label();
			this.textTime = new System.Windows.Forms.TextBox();
			this.label2 = new System.Windows.Forms.Label();
			this.label3 = new System.Windows.Forms.Label();
			this.textResultM = new System.Windows.Forms.TextBox();
			this.buttonRun = new System.Windows.Forms.Button();
			this.textResultR = new System.Windows.Forms.TextBox();
			this.textResultT = new System.Windows.Forms.TextBox();
			this.textAverageT = new System.Windows.Forms.TextBox();
			this.label5 = new System.Windows.Forms.Label();
			this.textAverageR = new System.Windows.Forms.TextBox();
			this.textAverageM = new System.Windows.Forms.TextBox();
			this.checkDomain = new System.Windows.Forms.CheckBox();
			this.buttonClear = new System.Windows.Forms.Button();
			this.radioRethrowNew = new System.Windows.Forms.RadioButton();
			this.radioComplex = new System.Windows.Forms.RadioButton();
			this.groupBox1.SuspendLayout();
			this.groupBox2.SuspendLayout();
			this.SuspendLayout();
			// 
			// groupBox1
			// 
			this.groupBox1.Controls.Add(this.radioRethrowNew);
			this.groupBox1.Controls.Add(this.radioCatch);
			this.groupBox1.Controls.Add(this.radioRethrow);
			this.groupBox1.Controls.Add(this.radioThrow);
			this.groupBox1.Controls.Add(this.radioNoException);
			this.groupBox1.Location = new System.Drawing.Point(24, 24);
			this.groupBox1.Name = "groupBox1";
			this.groupBox1.Size = new System.Drawing.Size(200, 152);
			this.groupBox1.TabIndex = 0;
			this.groupBox1.TabStop = false;
			this.groupBox1.Text = "Mode";
			// 
			// radioCatch
			// 
			this.radioCatch.Location = new System.Drawing.Point(16, 48);
			this.radioCatch.Name = "radioCatch";
			this.radioCatch.Size = new System.Drawing.Size(168, 24);
			this.radioCatch.TabIndex = 2;
			this.radioCatch.Text = "Catch without exception";
			this.radioCatch.CheckedChanged += new System.EventHandler(this.radioCatch_CheckedChanged);
			// 
			// radioRethrow
			// 
			this.radioRethrow.Location = new System.Drawing.Point(16, 96);
			this.radioRethrow.Name = "radioRethrow";
			this.radioRethrow.Size = new System.Drawing.Size(176, 24);
			this.radioRethrow.TabIndex = 4;
			this.radioRethrow.Text = "Rethrow original";
			this.radioRethrow.CheckedChanged += new System.EventHandler(this.radioRethrow_CheckedChanged);
			// 
			// radioThrow
			// 
			this.radioThrow.Location = new System.Drawing.Point(16, 72);
			this.radioThrow.Name = "radioThrow";
			this.radioThrow.TabIndex = 3;
			this.radioThrow.Text = "Throw";
			this.radioThrow.CheckedChanged += new System.EventHandler(this.radioThrow_CheckedChanged);
			// 
			// radioNoException
			// 
			this.radioNoException.Location = new System.Drawing.Point(16, 24);
			this.radioNoException.Name = "radioNoException";
			this.radioNoException.TabIndex = 1;
			this.radioNoException.Text = "No exception";
			this.radioNoException.CheckedChanged += new System.EventHandler(this.radioNoException_CheckedChanged);
			// 
			// groupBox2
			// 
			this.groupBox2.Controls.Add(this.radioComplex);
			this.groupBox2.Controls.Add(this.radioDatabase);
			this.groupBox2.Controls.Add(this.radioFile);
			this.groupBox2.Controls.Add(this.radioString);
			this.groupBox2.Controls.Add(this.radioEmpty);
			this.groupBox2.Location = new System.Drawing.Point(248, 24);
			this.groupBox2.Name = "groupBox2";
			this.groupBox2.Size = new System.Drawing.Size(200, 152);
			this.groupBox2.TabIndex = 4;
			this.groupBox2.TabStop = false;
			this.groupBox2.Text = "Job type";
			// 
			// radioDatabase
			// 
			this.radioDatabase.Location = new System.Drawing.Point(16, 96);
			this.radioDatabase.Name = "radioDatabase";
			this.radioDatabase.Size = new System.Drawing.Size(144, 24);
			this.radioDatabase.TabIndex = 8;
			this.radioDatabase.Text = "Database";
			this.radioDatabase.CheckedChanged += new System.EventHandler(this.radioDatabase_CheckedChanged);
			// 
			// radioFile
			// 
			this.radioFile.Location = new System.Drawing.Point(16, 72);
			this.radioFile.Name = "radioFile";
			this.radioFile.TabIndex = 7;
			this.radioFile.Text = "File access";
			this.radioFile.CheckedChanged += new System.EventHandler(this.radioFile_CheckedChanged);
			// 
			// radioString
			// 
			this.radioString.Location = new System.Drawing.Point(16, 48);
			this.radioString.Name = "radioString";
			this.radioString.Size = new System.Drawing.Size(160, 24);
			this.radioString.TabIndex = 6;
			this.radioString.Text = "String processing";
			this.radioString.CheckedChanged += new System.EventHandler(this.radioString_CheckedChanged);
			// 
			// radioEmpty
			// 
			this.radioEmpty.Location = new System.Drawing.Point(16, 24);
			this.radioEmpty.Name = "radioEmpty";
			this.radioEmpty.TabIndex = 5;
			this.radioEmpty.Text = "Empty";
			this.radioEmpty.CheckedChanged += new System.EventHandler(this.radioEmpty_CheckedChanged);
			// 
			// label1
			// 
			this.label1.Location = new System.Drawing.Point(24, 208);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(48, 16);
			this.label1.TabIndex = 9;
			this.label1.Text = "Time:";
			// 
			// textTime
			// 
			this.textTime.Location = new System.Drawing.Point(80, 200);
			this.textTime.Name = "textTime";
			this.textTime.Size = new System.Drawing.Size(72, 22);
			this.textTime.TabIndex = 10;
			this.textTime.Text = "";
			this.textTime.TextChanged += new System.EventHandler(this.textTime_TextChanged);
			// 
			// label2
			// 
			this.label2.Location = new System.Drawing.Point(160, 208);
			this.label2.Name = "label2";
			this.label2.Size = new System.Drawing.Size(56, 16);
			this.label2.TabIndex = 11;
			this.label2.Text = "seconds";
			// 
			// label3
			// 
			this.label3.Location = new System.Drawing.Point(264, 208);
			this.label3.Name = "label3";
			this.label3.Size = new System.Drawing.Size(64, 16);
			this.label3.TabIndex = 12;
			this.label3.Text = "Result:";
			// 
			// textResultM
			// 
			this.textResultM.Location = new System.Drawing.Point(344, 200);
			this.textResultM.Name = "textResultM";
			this.textResultM.ReadOnly = true;
			this.textResultM.Size = new System.Drawing.Size(32, 22);
			this.textResultM.TabIndex = 13;
			this.textResultM.Text = "";
			this.textResultM.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
			// 
			// buttonRun
			// 
			this.buttonRun.Location = new System.Drawing.Point(144, 280);
			this.buttonRun.Name = "buttonRun";
			this.buttonRun.Size = new System.Drawing.Size(88, 23);
			this.buttonRun.TabIndex = 15;
			this.buttonRun.Text = "Run";
			this.buttonRun.Click += new System.EventHandler(this.buttonRun_Click);
			// 
			// textResultR
			// 
			this.textResultR.Location = new System.Drawing.Point(408, 200);
			this.textResultR.Name = "textResultR";
			this.textResultR.ReadOnly = true;
			this.textResultR.Size = new System.Drawing.Size(32, 22);
			this.textResultR.TabIndex = 16;
			this.textResultR.Text = "";
			this.textResultR.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
			// 
			// textResultT
			// 
			this.textResultT.Location = new System.Drawing.Point(376, 200);
			this.textResultT.Name = "textResultT";
			this.textResultT.ReadOnly = true;
			this.textResultT.Size = new System.Drawing.Size(32, 22);
			this.textResultT.TabIndex = 17;
			this.textResultT.Text = "";
			this.textResultT.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
			// 
			// textAverageT
			// 
			this.textAverageT.Location = new System.Drawing.Point(376, 232);
			this.textAverageT.Name = "textAverageT";
			this.textAverageT.ReadOnly = true;
			this.textAverageT.Size = new System.Drawing.Size(32, 22);
			this.textAverageT.TabIndex = 17;
			this.textAverageT.Text = "";
			this.textAverageT.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
			// 
			// label5
			// 
			this.label5.Location = new System.Drawing.Point(264, 240);
			this.label5.Name = "label5";
			this.label5.Size = new System.Drawing.Size(64, 16);
			this.label5.TabIndex = 12;
			this.label5.Text = "Average:";
			// 
			// textAverageR
			// 
			this.textAverageR.Location = new System.Drawing.Point(408, 232);
			this.textAverageR.Name = "textAverageR";
			this.textAverageR.ReadOnly = true;
			this.textAverageR.Size = new System.Drawing.Size(32, 22);
			this.textAverageR.TabIndex = 16;
			this.textAverageR.Text = "";
			this.textAverageR.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
			// 
			// textAverageM
			// 
			this.textAverageM.Location = new System.Drawing.Point(344, 232);
			this.textAverageM.Name = "textAverageM";
			this.textAverageM.ReadOnly = true;
			this.textAverageM.Size = new System.Drawing.Size(32, 22);
			this.textAverageM.TabIndex = 13;
			this.textAverageM.Text = "";
			this.textAverageM.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
			// 
			// checkDomain
			// 
			this.checkDomain.Location = new System.Drawing.Point(32, 240);
			this.checkDomain.Name = "checkDomain";
			this.checkDomain.Size = new System.Drawing.Size(200, 24);
			this.checkDomain.TabIndex = 18;
			this.checkDomain.Text = "Execute in a separate domain";
			// 
			// buttonClear
			// 
			this.buttonClear.Location = new System.Drawing.Point(240, 280);
			this.buttonClear.Name = "buttonClear";
			this.buttonClear.Size = new System.Drawing.Size(88, 23);
			this.buttonClear.TabIndex = 15;
			this.buttonClear.Text = "Clear";
			this.buttonClear.Click += new System.EventHandler(this.buttonClear_Click);
			// 
			// radioRethrowNew
			// 
			this.radioRethrowNew.Location = new System.Drawing.Point(16, 120);
			this.radioRethrowNew.Name = "radioRethrowNew";
			this.radioRethrowNew.TabIndex = 5;
			this.radioRethrowNew.Text = "Rethrow new";
			this.radioRethrowNew.CheckedChanged += new System.EventHandler(this.radioRethrowNew_CheckedChanged);
			// 
			// radioComplex
			// 
			this.radioComplex.Location = new System.Drawing.Point(16, 120);
			this.radioComplex.Name = "radioComplex";
			this.radioComplex.Size = new System.Drawing.Size(144, 24);
			this.radioComplex.TabIndex = 9;
			this.radioComplex.Text = "Complex";
			this.radioComplex.CheckedChanged += new System.EventHandler(this.radioComplex_CheckedChanged);
			// 
			// MainForm
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
			this.ClientSize = new System.Drawing.Size(472, 320);
			this.Controls.Add(this.checkDomain);
			this.Controls.Add(this.textResultR);
			this.Controls.Add(this.textTime);
			this.Controls.Add(this.textResultM);
			this.Controls.Add(this.buttonRun);
			this.Controls.Add(this.label3);
			this.Controls.Add(this.label2);
			this.Controls.Add(this.label1);
			this.Controls.Add(this.groupBox2);
			this.Controls.Add(this.groupBox1);
			this.Controls.Add(this.textResultT);
			this.Controls.Add(this.textAverageT);
			this.Controls.Add(this.label5);
			this.Controls.Add(this.textAverageR);
			this.Controls.Add(this.textAverageM);
			this.Controls.Add(this.buttonClear);
			this.Name = "MainForm";
			this.Text = "Exception Performance";
			this.groupBox1.ResumeLayout(false);
			this.groupBox2.ResumeLayout(false);
			this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new MainForm());
		}

		private void buttonRun_Click(object sender, System.EventArgs e)
		{
			int seconds = 0;
			try
			{
				seconds = Convert.ToInt32(this.textTime.Text);
			}
			catch(Exception)
			{
			}

			if(seconds > 0)
			{
				this.timer = new System.Timers.Timer(seconds * 1000);
				this.timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
				this.timer.AutoReset = false;
				this.timer.Enabled = true;

				ExecuteDelegate execute = null;
				if(this.radioNoException.Checked)
					execute = new ExecuteDelegate(ExceptionMode.None);
				else if(this.radioCatch.Checked)
					execute = new ExecuteDelegate(ExceptionMode.Catch);
				else if(this.radioThrow.Checked)
					execute = new ExecuteDelegate(ExceptionMode.Throw);
				else if(this.radioRethrow.Checked)
					execute = new ExecuteDelegate(ExceptionMode.Rethrow);
				else if(this.radioRethrowNew.Checked)
					execute = new ExecuteDelegate(ExceptionMode.RethrowNew);

				if(this.checkDomain.Checked)
				{
					string asmName = typeof(Job).Assembly.FullName;
					string typeName = typeof(Job).FullName;
					jobHost = domain.CreateInstanceAndUnwrap(asmName, typeName) as Job;
				}
				else
				{
					jobHost = new Job();
				}
				jobHost.Empty(false);

				JobDelegate job = null;
				if(this.radioEmpty.Checked)
					job = new JobDelegate(jobHost.Empty);
				else if(this.radioString.Checked)
					job = new JobDelegate(jobHost.String);
				else if(this.radioFile.Checked)
					job = new JobDelegate(jobHost.File);
				else if(this.radioDatabase.Checked)
					job = new JobDelegate(jobHost.Database);
				else if(this.radioComplex.Checked)
					job = new JobDelegate(jobHost.Complex);

				PerformanceTest test = new PerformanceTest(execute, job);
				while(this.timer.Enabled)
				{
					test.Execute();
				}

				DisplayResults(test.Count, this.textResultM, this.textResultT, this.textResultR);
				averageResult = (resultCount * averageResult + test.Count) / (resultCount + 1);
				++resultCount;
				DisplayResults(averageResult, this.textAverageM, this.textAverageT, this.textAverageR);
			}
		}

		private void buttonClear_Click(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private static void OnTimedEvent(object source, ElapsedEventArgs e) 
		{
		}

		private void radioNoException_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void radioCatch_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void radioThrow_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void radioRethrow_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void radioRethrowNew_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void radioEmpty_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void radioString_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void radioFile_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void radioDatabase_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void textTime_TextChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void radioComplex_CheckedChanged(object sender, System.EventArgs e)
		{
			ClearResults();
		}

		private void ClearResults()
		{
			this.textResultM.Clear();
			this.textResultT.Clear();
			this.textResultR.Clear();
			this.textAverageM.Clear();
			this.textAverageT.Clear();
			this.textAverageR.Clear();

			averageResult = 0;
			resultCount = 0;
		}

		private void DisplayResults(long count, TextBox textM, TextBox textT, TextBox textR)
		{
			long millions = count / 1000000;
			long thousands = (count - millions * 1000000) / 1000;
			long remainder = count - millions * 1000000 - thousands * 1000;
			if(millions > 0)
				textM.Text = string.Format("{0}", millions);
			else
				textM.Clear();
			if(thousands > 0)
				if(millions > 0)
					textT.Text = string.Format("{0:D3}", thousands);
				else
					textT.Text = string.Format("{0}", thousands);
			else
				textT.Clear();
			if(millions > 0 || thousands > 0)
				textR.Text = string.Format("{0:D3}", remainder);
			else
				textR.Text = string.Format("{0}", remainder);
		}

		private void InitAppDomain()
		{
			// Set up the AppDomainSetup
			AppDomainSetup setup = new AppDomainSetup();
			setup.ApplicationBase = System.IO.Directory.GetCurrentDirectory();

			// Set up the Evidence
			Evidence evidence = AppDomain.CurrentDomain.Evidence;

			domain = AppDomain.CreateDomain("AppDomain", evidence, setup);
		}

		private System.Timers.Timer timer;
		private long averageResult = 0;
		private int resultCount = 0;
		private static AppDomain domain = null;
		private Job jobHost = null;
	}

	public delegate void ExecuteDelegate(JobDelegate job);
	public delegate void JobDelegate(bool throwException);

	public class PerformanceTest
	{
		public PerformanceTest(ExecuteDelegate execute, JobDelegate job)
		{
			this.execute = execute;
			this.job = job;
		}

		public void Execute()
		{
			this.execute(this.job);
			++count;
		}

		private ExecuteDelegate execute;
		private JobDelegate job;

		private long count = 0;
		public long Count
		{
			get { return count; }
		}
	}

	public class ExceptionMode
	{
		private ExceptionMode()
		{
		}

		public static void None(JobDelegate job)
		{
			job(false);
		}

		public static void Catch(JobDelegate job)
		{
			try
			{
				job(false);
			}
			catch(Exception)
			{
			}
		}

		public static void Throw(JobDelegate job)
		{
			try
			{
				job(true);
			}
			catch(Exception)
			{
			}
		}

		public static void Rethrow(JobDelegate job)
		{
			try
			{
				try
				{
					job(true);
				}
				catch(Exception)
				{
					throw;
				}
			}
			catch(Exception)
			{
			}
		}

		public static void RethrowNew(JobDelegate job)
		{
			try
			{
				try
				{
					job(true);
				}
				catch(Exception ex)
				{
					throw new System.NullReferenceException(string.Empty, ex);
				}
			}
			catch(Exception)
			{
			}
		}
	}

	public class Job : MarshalByRefObject
	{
		public Job()
		{
		}

		public void Empty(bool throwException)
		{
			if(throwException)
				throw new System.NullReferenceException();
		}

		public void String(bool throwException)
		{
			string test = "The quick brown fox jumps over the lazy dog";
			string[] words = test.Split(' ');
			foreach(string word in words)
			{
				string newWord = word.ToUpper();
			}

			if(throwException)
				throw new System.NullReferenceException();
		}

		public void File(bool throwException)
		{
			DirectoryInfo di = new DirectoryInfo(Directory.GetCurrentDirectory());
			foreach(FileSystemInfo fi in di.GetFileSystemInfos())
			{
				if((fi.Attributes & FileAttributes.Directory) == 0)
				{
					FileStream stream = System.IO.File.OpenRead(fi.Name);
					byte[] buffer = new byte[stream.Length];
					stream.Read(buffer, 0, buffer.Length);
					stream.Close();
				}
			}

			if(throwException)
				throw new System.NullReferenceException();
		}

		public void Database(bool throwException)
		{
			SqlConnection con = new SqlConnection(@"Data Source=;Initial Catalog=Northwind;User ID=sa;Password=password");
			SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Products", con);
			DataSet ds = new DataSet();
			adapter.Fill(ds);
			foreach(DataRow row in ds.Tables[0].Rows)
			{
				for(int col = 0; col < ds.Tables[0].Columns.Count; col++)
				{
					string val = row[col].ToString();
				}
			}

			if(throwException)
				throw new System.NullReferenceException();
		}

		public void Complex(bool throwException)
		{
			String(false);
			File(false);
			String(false);
			Database(false);
			String(false);
			File(false);
			String(false);

			String(false);
			File(false);
			String(false);
			Database(false);
			String(false);
			File(false);
			String(false);

			if(throwException)
				throw new System.NullReferenceException();
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Miles AS
Norway Norway
Vagif Abilov is a Russian/Norwegian software developer and architect working for Miles. He has more than twenty years of programming experience that includes various programming languages, currently using mostly C# and F#.

Vagif writes articles and speaks at user group sessions and conferences. He is a contributor and maintainer of several open source projects, including Simple.Data OData adapter, Simple.OData.Client and MongOData.

Comments and Discussions