Question

I am not understanding how this compiles.

I have a VB.net class with the following:

Public Class Line
    Public Enum EligibleType
        skipNone = 0
        skipAllow = 1
        skipPay = 2
        skipDeleted = 4
        skipMod = 8
        skipOverride = 16
    End Enum

    Public Function Eligible(Optional ByRef enmEligibleFlag As Line.EligibleType = Line.EligibleType.brSkipNone) As Boolean
End Class

This is called over 9,000 times in the application. I tried to write a test method in C# for another function and used Rhino Mocks to create a stub of the class. Then I stubbed the function to always return true. It would not compile.

[TestClass]
public class breMATest
{
    /// <summary>
    /// Tests the 102.
    /// </summary>
    [TestMethod]
    public void Test102()
    {
        // Arrange
        br target = new br();
        var line = MockRepository.GenerateStub<Line>();
        line.Stub(s => s.Eligible(ref Arg<Line.EligibleType>.Ref(brBD.Line.EligibleType, Line.EligibleType.skipNone).Dummy).Return(true);

        // Act
        target.Pay102(ref line);

        // Assert
    }
}

This gives me:

    CS1510: A ref or out argument must be an assignable variable
 UnitTestsCS\brTest.cs(35,13,35,71): error CS1502: The best overloaded method match for 'brBD.Line.Eligible(ref brBD.Line.EligibleType)' has some invalid arguments

I tried this as well, with the same results:

line.Stub(s => s.Eligible(brBD.Line.EligibleType.skipNone)).Return(true);

I tried calling it directly, same error:

line.Eligible(ref brBD.Line.EligibleType.skipNone));

I understand the error. You can’t pass an enumeration by reference because an enumeration is a constant and can’t be assigned. So I have two questions:

  1. Is there a way to stub this to always return true?
  2. Why does this work in VB.NET?

Thanks in advance,

Tim

Was it helpful?

Solution

The thing you are passing as ref is:

Arg<Line.EligibleType>
  .Ref(brBD.Line.EligibleType, Line.EligibleType.skipNone).Dummy

Now; we can't see Arg<T>.Ref, but I'm guessing it returns a class upon which .Dummy is a property. In C# you can't pass a property as a ref. I imagine VB elects to spoof this, essentially doing the equivalent of:

var tmp = Arg<Line.EligibleType>.Ref(brBD.Line.EligibleType, Line.EligibleType.skipNone).Dummy;
return s.Eligible(ref tmp)

However, C# chooses not to work this way. IIRC, VB also allows ref to be implicit, so there are some very different design aims around how ref should be treated.

But I have to agree with C# - in the ref usage, you aren't really passing a "reference to the property", so for me at least, it avoids incorrect usage to work the way it does - even if that is more explicit.

As an aside: if .Dummy was a field, then you can pass it as ref; however, this should not be interpreted as "make .Dummy a field"; that is very much not what I said ;p

I understand the error. You can’t pass an enumeration by reference because an enumeration is a constant and can’t be assigned.

You can pass references to fields, references to local variables / parameters, and references to things in array as ref; those things can be typed as enumerations.

OTHER TIPS

Write your stub like this:

Line.EligibleType et = Line.EligibleType.SkipNone;
line.Stub(s => s.Eligible(ref et))
    .OutRef(Line.EligibleType.skipNone).Return(true);

A ref has to be assignable. You can't pass a constant.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top