I'm writing a little VBA IDE add-in, and there's a COM-visible C# class called AssertClass
, with an AreEqual
method that goes like this:
public void AreEqual(object value1, object value2, string message = null)
{
if (value1.Equals(value2))
{
AssertHandler.OnAssertSucceeded();
}
else
{
AssertHandler.OnAssertFailed("AreEqual", message);
}
}
When the client VBA code calls it like this, all works as expected:
'@TestMethod
Public Sub TestMethod1()
'compares two identical Integer (Int16) values:
Assert.AreEqual 2, 2
End Sub
However when the client VBA code passes different types, it fails:
'@TestMethod
Public Sub TestMethod2()
'compares identically-valued Long (Int32) and Integer (Int16) values:
Assert.AreEqual CLng(2), 2
End Sub
When TestMethod2
calls Assert.AreEqual
, the .NET code receives an int
and a short
- which is correct... but I don't want to put it on the client VBA code to make sure it's passing the same types - I'd want all these calls to result in a succeeding assertion:
Assert.AreEqual CByte(2), 2 'fails
Assert.AreEqual CInt(2), 2 'passes
Assert.AreEqual CLng(2), 2 'fails
Assert.AreEqual CSng(2), 2 'fails
Assert.AreEqual CDbl(2), 2 'fails
Assert.AreEqual CCur(2), 2 'fails
After all, VBA isn't as strict as C# when it comes to type safety and equality checks:
?CByte(2) = 2, CInt(2) = 2, CLng(2) = 2, CSng(2) = 2, CDbl(2) = 2, CCur(2) = 2
True True True True True True
How can I formulate my AreEqual
C# function so as to... somehow avoid forcing type safety into the VBA client code? I cannot assume that the VBA client code is going to pass numeric values - the method needs to also work with String
and Date
values.
I'm stumped. Is my only option to document the fact that types matter?
Using C# 4.5 in VS 2013 Express.
This is a bit of a shot in the dark (haven't worked with VBA & C# combination), but try this and see if it works:
public void AreEqual(object value1, object value2, string message = null)
{
bool convertedOk = true;
object value2Converted;
try
{
value2Converted = Convert.ChangeType(value2, value1.GetType());
}
catch
{
convertedOk = false;
}
if (convertedOk && value1.Equals(value2Converted))
{
AssertHandler.OnAssertSucceeded();
}
else
{
AssertHandler.OnAssertFailed("AreEqual", message);
}
}
Idea being that you change type of second value that that of first so they now become "more compatilbe" for comparison.
EDIT: Updated answer with try/catch handling as suggested by comments. Thanks!