User:Henon
From eqqon
C# Knowhow :: Piccolo Snippets
Contents |
Henon's Blog
Ruby-like instance @variables in C#
Although I am very impressed by C#, Ruby is still my favorite programming language because of it's clean design and unreached flexibility. One of the things I like about Ruby is its way to mark instance variables (in Ruby's terminology) or member variables / fields (in C# terminology). They are prefixed with the @-sign. This makes code very easy to read. To get the same effect most C# programmers rely on a kind of Hungarian style notation which means prefixing with m_. Today I discovered that the C# compiler allows the @-sign as prefix for identifiers. This is useful if you need to name an identifier e.g. a variable like a keyword. How often have I been forced to unwillingly name variables which contain a class-object klass or _class when programming in Ruby. So this is really a nice feature of C#, isn't it?
Even better, the @-prefix can also be used to mark member variables in C#. Since I am virulently against the Hungarian notation for variable names (e.g. lpSzFile) this is exactly what I was looking for. Now programming C# feels much more like Ruby for me. There are still many oddities in C# which I need to get used to or even better I need to overcome by using the new extension methods introduced by C# 3.0.
Example: The class Range
Here is the Range class, a built in Ruby feature which I instantly missed the first day I started programming C#. It is based on the class Range by Goran Mitrovic. I refactored it a bit and applied the @-notation. Those of you who love Ruby will love this style:
using System;
using System.Collections;
namespace Eqqon
{
public struct Range : ICollection, IEnumerable
{
public Range(int startValue, int endValue)
{
@start = startValue;
@end = 0;
this.End = endValue;
}
public Range(ICollection col)
{
@start = 0;
@end = ((col != null) ? col.Count : 0) - 1;
}
public int Start
{
get { return @start; }
set
{
@start = value;
if (@end < (@start - 1)) @end = @start - 1;
}
}
public int End
{
get { return @end; }
set
{
@end = (value >= @start) ? value : (@start - 1);
}
}
public int Mid
{
get
{
return (@start + @end) / 2;
}
}
public void Set(int start, int end)
{
@start = start;
this.End = end;
}
public bool Contains(int value)
{
return (@start <= value) && (value <= @end);
}
public static bool Contains(int left, int value, int right)
{
return (left <= value) && (value <= right);
}
public int Saturate(int value)
{
return (value > @start) ? ((value < @end) ? value : @end) : @start;
}
public static int Saturate(int left, int value, int right)
{
return (value > left) ? ((value < right) ? value : right) : left;
}
public static Range operator &(Range r1, Range r2)
{
return new Range(Math.Max(r1.Start, r2.Start), Math.Min(r1.End, r2.End));
}
public static Range operator |(Range r1, Range r2)
{
return new Range(Math.Min(r1.Start, r2.Start), Math.Max(r1.End, r2.End));
}
public void Offset(int o)
{
@start += o;
@end += o;
}
public void Resize(int s)
{
End += s;
}
public int Count
{
get { return @end - @start + 1; }
}
public bool Empty
{
get { return @end == (@start - 1); }
}
public int this[int index]
{
get
{
if (Count == 0) throw new InvalidOperationException("Cannot perform this operation on a Range with Count 0!");
return @start + index % Count;
}
}
public void CopyTo(Array array, int index)
{
if (array == null) throw new ArgumentNullException("Array must not be null!");
if (index < 0) throw new ArgumentOutOfRangeException("index", index, "Index must not be < 0");
if (array.Rank != 1) throw new ArgumentException("Array must not be multidimensional.", "array");
if (!new Range(array).Contains(index)) throw new ArgumentOutOfRangeException("index");
if (Count == 0) return;
if (!new Range(array).Contains(index + Count - 1)) throw new ArgumentOutOfRangeException("index");
foreach (int i in this)
{
array.SetValue(i, index + i - @start);
}
}
public bool IsSynchronized
{
get { return false; }
}
public object SyncRoot
{
get { return this; }
}
public IEnumerator GetEnumerator()
{
return new Iterator(ref this);
}
private class Iterator : IEnumerator
{
public Iterator(ref Range r)
{
@range = r;
Reset();
}
public object Current
{
get
{
if (!@range.Contains(@pos + @range.Start)) throw new InvalidOperationException();
return @range[@pos];
}
}
public bool MoveNext()
{
return @range.Contains((++@pos) + @range.Start);
}
public void Reset()
{
@pos = -1;
}
private Range @range;
private int @pos;
};
private int @start;
private int @end;
}
}
Comments
If you like to comment my Blog entry, you are welcome to do so here.
- --Henon 22:18, 30 October 2007 (CET)