Is it a bug or by-design? Calling vb.net extension function from C# via addmodule.

Coordinator
May 11, 2015 at 5:56 PM
Edited May 11, 2015 at 6:19 PM
I am writing a c# test case string_null_or_whitespace_perf.cs with an external module compiled from vb.net source code char_detection.vb.
The build commands,
vbc /target:module /out:tmp.mod /define:NO_REFERENCE /rootnamespace:osi.root.connector ..\..\..\connector\string_utils\char_detection.vb
csc /target:module /addmodule:tmp.mod /out:tmp2.mod string_null_or_whitespace_perf.cs
link /entry:string_null_or_whitespace_perf.Main /out:string_null_or_whitespace_perf.exe /LTCG /SUBSYSTEM:CONSOLE tmp.mod tmp2.mod
del tmp.mod
del tmp2.mod
The char_detection.vb contains two extension functions,

Imports System.Runtime.CompilerServices
#If Not NO_REFERENCE Then
Imports osi.root.constants
#End If

Public Module _char_detection
    <Extension()> Public Function null_or_empty(ByVal s As String) As Boolean
        Return String.IsNullOrEmpty(s)
    End Function

    <Extension()> Public Function null_or_whitespace(ByVal s As String) As Boolean
        If s.null_or_empty() Then
            Return True
        Else
#If NO_REFERENCE Then
            For i As Int32 = 0 To s.Length() - 1
                If Not Char.IsWhiteSpace(s(i)) Then
#Else
            For i As UInt32 = 0 To strlen(s) - uint32_1
                If Not s(i).space() Then
#End If
                    Return False
                End If
            Next
            Return True
        End If
    End Function
End Module
While in string_null_or_whitespace_perf.cs, I actively call one of the extension function,
// Targeting .net 4.0 or upper
using System;
using System.Diagnostics;
using System.IO;
using osi.root.connector;

public static class string_null_or_whitespace_perf
{
    private static string[] strs =
    {
        "",
        new string(' ', 1024),
        string.Concat(new string(' ', 1024), new string('a', 1024)),
        string.Concat(new string('a', 1024), new string(' ', 1024)),
        "a",
        new string('a', 1024),
        string.Concat("a", new string(' ', 1024), "a"),
        string.Concat(" ", new string('a', 1024), " "),
    };

    static string_null_or_whitespace_perf()
    {
        _char_detection.null_or_whitespace("");  // **1
    }

    private static void internal_func(long round)
    {
        for (long i = 0; i < round; i++)
        {
            string.IsNullOrWhiteSpace(strs[i % strs.Length]);
        }
    }

    private static void implemented_func(long round)
    {
        _char_detection.null_or_whitespace("");  // **2
        for (long i = 0; i < round; i++)
        {
            strs[i % strs.Length].null_or_whitespace();
        }
    }

    public static int Main(string[] args)
    {
        const long round = 1024L * 1024 * 1024;
        long int_ticks;
        Stopwatch watch = Stopwatch.StartNew();
        internal_func(round);
        int_ticks = watch.Elapsed.Ticks;
        long impl_ticks;
        watch = Stopwatch.StartNew();
        implemented_func(round);
        impl_ticks = watch.Elapsed.Ticks;

        Console.WriteLine("internal_func: " + int_ticks.ToString());
        Console.WriteLine("implemented_func: " + impl_ticks.ToString());
        if (impl_ticks * 1.0 / int_ticks >= 1.5)
            return -1;
        return 0;
    }
}
But if I commented out both **1 and **2, the compilation will fail, as,
string_null_or_whitespace_perf.cs(40,35): error CS1061: 'string' does not contain a definition for 'null_or_whitespace' and no extension method 'null_or_whitespace' accepting a first argument of type 'string' could be found (are you missing a using directive or an assembly reference?)

Interesting, but is it by-design?