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

Était-ce utile?

La 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.

Autres conseils

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top