|
| Cook Computing
Mainly technical stuff from Charles Cook
@mentalguy must have been having a frustrating day:
I've come across this problem with .NET code. Often a single exception type will cover several different error conditions and so when writing the corresponding unit tests it's tempting to assert on the exception's Message property. Of course this is bad because it assumes the text of the message won't be changed.
NUnit
NUnit encourages the checking of exception messages when using the ExpectedException attribute, for example
[ExpectedException(typeof(ArgumentException), ExpectedMessage="expected message" )]
but suggests that this is not good practice by allowing you to match on a substring or a regular expression:
public enum MessageMatch
{
/// Expect an exact match
Exact,
/// Expect a message containing the parameter string
Contains,
/// Match the regular expression provided as a parameter
Regex
}
For example, this is for a test that passes only if an ArgumentException with a message containing "unspecified" is received.
[ExpectedException(typeof(ArgumentException),
ExpectedMessage="unspecified", MatchType=MessageMatch.Contains)]
public void TestMethod()
{
...
}
It's better to have some way of specifying an error code which can be checked independently of the message, for example say we have an exception base class supporting an error code from which we derive custom exception classes:
public class ExceptionBase : Exception
{
public ExceptionBase(int errorCode, string message)
: this(errorCode, message, null)
{
}
public ExceptionBase(int errorCode, string message, Exception innerException)
: base(message, innerException)
{
ErrorCode = errorCode;
}
public int ErrorCode { get; private set; }
}
public class MessageException : ExceptionBase
{
public MessageException(int errorCode, string message)
: base(errorCode, message)
{
}
public MessageException(int errorCode, string message, Exception innerException)
: base(errorCode, message, innerException)
{
}
}
We can test for exceptions with a particular error code like this:
[TestFixture]
public class Tests
{
[Test]
public void Test1()
{
MessageException ex = Assert.Throws<MessageException>(() =>
{
// code which is expected to throw the exception
// ...
}
);
Assert.AreEqual(ErrorCodes.HEADER_MISSING, ex.ErrorCode);
}
}
Visual Studio
Visual Studio does the right thing and doesn't have a built-in way of checking the exception message. You can even use your own attributes derived from its ExpectedExceptionBaseAttribute class. This allows us to implement an attribute which can be used to check the error code in exception classes derived from the above ExceptionBase class:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class ExpectedExceptionWithErrorCode : ExpectedExceptionBaseAttribute
{
public Type ExpectedException { get; set; }
public int ExpectedErrorCode { get; set; }
public ExpectedExceptionWithErrorCode(Type expectedException)
: this(expectedException, 0, "")
{
}
public ExpectedExceptionWithErrorCode(Type expectedException,
int errorCode)
: this(expectedException, errorCode, "")
{
}
public ExpectedExceptionWithErrorCode(Type expectedException,
int errorCode, string noExceptionMessage)
: base(noExceptionMessage)
{
if (expectedException == null)
throw new ArgumentNullException("exceptionType");
if (!typeof(Exception).IsAssignableFrom(expectedException))
throw new ArgumentException("Expected exception type must be "
+ "System.Exception or derived from System.Exception.",
"expectedException");
ExpectedException = expectedException;
ExpectedErrorCode = errorCode;
}
protected override void Verify(Exception exception)
{
if (exception.GetType() != ExpectedException)
{
base.RethrowIfAssertException(exception);
string msg = string.Format("Test method {0}.{1} "
+ "threw exception {2} but {3} was expected.",
base.TestContext.FullyQualifiedTestClassName, base.TestContext.TestName,
exception.GetType().FullName, ExpectedException.FullName);
throw new Exception(msg);
}
ExceptionBase ex = exception as ExceptionBase;
if (ex.ErrorCode != ExpectedErrorCode)
{
string msg = string.Format("Test method {0}.{1} threw expected "
+ "exception {2} with error code {4} but error code {5} was expected.",
base.TestContext.FullyQualifiedTestClassName, base.TestContext.TestName,
exception.GetType().FullName, ExpectedException.FullName,
ex.ErrorCode, ExpectedErrorCode);
throw new Exception(msg);
}
}
}
This can be used like this:
[TestClass]
public class Tests
{
[TestMethod]
[ExpectedExceptionWithErrorCode(typeof(MessageException),
ExpectedErrorCode = ErrorCodes.INVALID_HEADER)]
public void Test1()
{
// code which is expected to throw the exception
// ...
}
}
While looking at collection initializers I came across
mucking about with hashes... and
more mucking about with hashes by Alex Henderson (via
Phil Haack). In these posts he describes ways of creating an instance of a string-keyed Dictionary in a Ruby-like way using lambda expressions, for example:
Dictionary<string, string> items = Hash(Age => "10", Height => "20");
The second post contains the fastest implementation (contributed by
Andrey Shcekin):
public Dictionary<string, T> Hash<T>(params Func<string, T>[] args)
where T : class
{
var items = new Dictionary<string, T>();
foreach (var func in args)
{
var item = func(null);
items.Add(func.Method.GetParameters()[0].Name, item);
}
return items;
}
[Comment: I don't see why the class constraint is necessary]
This led me to think that I could implement an Add extension method which would allow a collection initializer to be used, for example like this:
var items = new Dictionary<string, string> { Name => "alex", Age => "10" };
I came up with this:
static class Extensions
{
public static void Add<T>(this Dictionary<string, T> dict, Func<string, T> args)
{
var item = args(null);
dict.Add(args.Method.GetParameters()[0].Name, item);
}
}
Unfortunately, although this works fine when Add is invoked explicitly, it fails to compile when attempting to use it in a collection initializer. The compiler only recognizes member functions called Add, not extension methods. C# PM Alex Turner wrote on
Connect:
You're right that the spec is ambiguous here! There was no explicit decision in C# 3.0 to prevent this from working; it was simply an implementation limitation we accepted when we discovered it late in the product cycle. We see no design reason not to add this now, but unfortunately, we are starting to lock down on our feature set and won't be able to get to this feature for this release. We'll definitely keep this in mind when planning for our next release!
...I've added a vote for collection initializers binding to Add extension methods to the OneNote notebook we use internally to track C# compiler and language requests. We can't promise if or when we'll get to this feature, but we'll definitely keep it in mind during planning for the next release!
I tried this with the .NET 4.5 Developer Preview and it still fails to build, but of course this may change before the final release.
On the other hand, VB does support the use of extension methods called Add in collection initializers but its syntax for lambda expressions rather misses the point of the exercise:
Imports System.Runtime.CompilerServices
Module Sample
Sub Main()
Dim dict As New Dictionary(Of String, Integer) _
From { Function(Age As String) 10, Function(Height As String) 20 }
End Sub
<Extension()>
Sub Add(Of T)(ByVal dict As Dictionary(Of String, T),
ByVal args As Func(Of String, T))
Dim item As T
item = args(Nothing)
dict.Add(args.Method.GetParameters()(0).Name, item)
End Sub
End Module
While thinking about which features I would like added to C# I came across an old post by Eric Lippert ?
In Foof We Trust: A Dialogue ? in which he presents an imaginary dialog between himself and a C# user who would like an operator or operators similar to typeof() but which would take the name of a method, field, or property instead of a type name. I mentioned something similar in old posts
here and
here. This feature would certain reduce the need to hard-code method/property names or use lambda expressions, for example in implementations of INotifyPropertyChanged.PropertyChanged, and would help refactoring tools. It was interesting to read:
I agree, that would be a lovely sugar. This idea has been coming up during the C# design meeting for almost a decade now. We call the proposed operator ?infoof?, since it would return arbitrary metadata info. We whimsically insist that it be pronounced ?in-foof?, not ?info-of?.
He goes on to describe that there are design issues which make this much more costly to implement and test than it appears at first sight and that there are always budgetary constraints on which new features his team can deliver. He sums up:
It?s an awesome feature that pretty much everyone involved in the design process wishes we could do, but there are good practical reasons why we choose not to. If there comes a day when designing it and implementing it is the best way we could spend our limited budget, we?ll do it. Until then, use Reflection.
Looks like that one will remain on the wishlist but it turns out that one other feature I would like has already been implemented for some time now: collection initializers for dictionaries. For example, you can write this:
Dictionary<int, string> hashtable = new Dictionary<int, string>
{ { 1, "one" }, {2, "two" }, {3, "three" } };
This is a particular case of using a collection initializer which turns out to be a fairly complicated, not to say contrived, language feature. If your type implements IEnumerable ? presumably a sanity check that it represents some sort of collection ? and has one or more methods called Add(), the compiler will map the collection initializer expression onto calls to the Add() function(s). Mads Torgerson wrote about this in 2006: What is a collection?
I just came across an interesting exercise in analysing the design of product packaging. Design consultancy
Antrepo took several well-known brands and progressively stripped away the packaging detail on each of them. Along with several of the people commenting on the post I mostly prefer the third versions of each product. These are not as busy as the first and second but still retain something of the brand identity. They might be too simple in the long run though ? perhaps the richness of the original versions is required to retain interest when you are exposed to the packaging over and over again. Or maybe I'm simply atypical of the target market.
ArraySegment
I was looking at an algorithm which involves processing segments of an array recursively and I thought the code would be neater if instead of passing the array plus the offset and length of each segment I could use an array data type which provides a view onto a segment of an array. The ArraySegment type appeared in search results and it's name sounded promising. I'd not heard of it before but it's been around since .NET 2.0 and is used in various types including Socket and LogRecordSequence. Unfortunately it is essentially just a way of specifying a segment and doesn't provide any methods to access the data within the segment:
public struct ArraySegment<T>
{
public ArraySegment(T[] array);
public ArraySegment(T[] array, int offset, int count);
public static bool operator !=(ArraySegment<T> a, ArraySegment<T> b);
public static bool operator ==(ArraySegment<T> a, ArraySegment<T> b);
public T[] Array { get; }
public int Count { get; }
public int Offset { get; }
public bool Equals(ArraySegment<T> obj);
public override bool Equals(object obj);
public override int GetHashCode();
}
It also doesn't have a constructor which takes an ArraySegment so making it awkward to use for recursive algorithms, but it's a ready-made class if you need to specify segments of an array without making copies of the array, as in this example.
SubArray
At first I thought it would be nice if SubArray was an array type but I quickly realized you cannot derive from System.Array. According to MSDN:
The Array class is the base class for language implementations that support arrays. However, only the system and compilers can derive explicitly from the Array class. Users should employ the array constructs provided by the language.
So it's not possible to create an array type which represents a sub-array. The solution was to implement a type which derives from IList<T>. This provides methods for indexing and enumerating the sub-array. The Java interface List has a method called subList which provides some prior art for this:
Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive. (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list, and vice-versa. The returned list supports all of the optional list operations supported by this list...
...The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
In the case of the new SubArray type we'll assume the underlying collection is an array, i.e. of fixed length, so the methods of IList<T> which change the length of the list will throw NotSupportedException. We will also allow an instance of a SubArray to be created as an offset into an existing SubArray (with the Offset property of the "sub-SubArray" referring to the original array and not to its parent SubArray). Finally as with ArraySegment the SubArray type will be a struct. Throw in some extension methods to make it easier to use and came up with this:
SubArray.cs
Example Usage
Reconstruct a binary tree from arrays containing the inorder and preorder traversal of the tree (assuming no duplicates).
public void Sample()
{
int[] preorder = { 7, 10, 4, 3, 1, 2, 8, 11 };
int[] inorder = { 4, 10, 3, 1, 7, 11, 8, 2 };
Node head = ReconstructTree(preorder, inorder);
}
Node ReconstructTree(int[] preorder, int[] inorder)
{
// use a hashtable to retrieve position of sub-root node from inorder array
var inorderMapTable = new Dictionary<int, int>(preorder.Length);
for (int i = 0; i < inorder.Length; i++)
inorderMapTable[inorder[i]] = i;
return ReconstructTreeHelper(preorder.SubArray(), inorder.SubArray(), inorderMapTable);
}
Node ReconstructTreeHelper(SubArray<int> preorder, SubArray<int> inorder,
Dictionary<int, int> inorderMapTable)
{
int rootVal = preorder[0];
int rootPos = inorderMapTable[rootVal] - inorder.Offset;
Node node = new Node { Id = rootVal };
int nodesToLeft = rootPos;
if (nodesToLeft > 0)
node.Left = ReconstructTreeHelper(preorder.SubArray(1, nodesToLeft),
inorder.SubArray(0, nodesToLeft), inorderMapTable);
int nodesToRight = inorder.Count - rootPos - 1;
if (nodesToRight > 0)
node.Right = ReconstructTreeHelper(preorder.SubArray(rootPos + 1, nodesToRight),
inorder.SubArray(rootPos + 1, nodesToRight), inorderMapTable);
return node;
}
The expected result is:
_______7______
/ \
__10__ ___2
/ \ /
4 3 _8
\ /
1 11
Postscript
It turns out that ArraySegment has richer functionality in .NET Framework 4.5 :
[SerializableAttribute]
public struct ArraySegment<T> : IList<T>, ICollection<T>, IReadOnlyList<T>,
IEnumerable<T>, IEnumerable
It still doesn't provide a way of creating a ArraySegment as a sub-array of an existing ArraySegment but it would be trivial to supply an extension method to add this functionality.
Newsfeed display by CaRP |