Search code examples
c#vbacom-interopequalitytype-safety

What if I don't want type safety?


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

TestMethod1 passes

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

TestMethod2 fails


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.


Solution

  • 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!