如何检测哪种.NET语言正在调用我的代码

Nat*_*ini 3 .net reflection cil

我正在构建一个库,该库生成一个用户代理字符串,该字符串报告一些漂亮的数据,如操作系统版本和当前安装的.NET Framework版本.我很好奇:

是否有可能以编程方式检测哪种语言正在调用我的库?或者,一旦编译成CIL,源语言是否完全不透明?

Nat*_*ini 5

编辑:我把它变成了一个小型库,它封装了一些启发式算法,可以很容易地调用它.

我提出了一种似乎适合我自己需要的启发式算法.

@Don回答,这些问题给了我一些提示:

警告:

  • 只区分VB.NET和C#,而不是任何其他CLR语言.假设C#没有足够的VB证据.
  • 它正在做出有根据的猜测,因此误报的可能性大于0.
  • 一些提示基于编译器实现细节,这可能会改变.
  • 这似乎也适用于Mono,但是YMMV.
  • 这是昂贵的反射,所以在现实生活中你想要将它包装在一个Lazy<>或一些其他机制中,以确保它只被调用一次.
  • 正如@HABO所提到的,这可能是也可能不是非常有用的信息.我很想知道是否可以做到.

var lang = DetectAssemblyLanguage(Assembly.GetCallingAssembly());

public static string DetectAssemblyLanguage(Assembly assembly)
{
    var referencedAssemblies = assembly
        .GetReferencedAssemblies()
        .Select(x => x.Name);

    var types = assembly
        .GetTypes();

    // Biggest hint: almost all VB.NET projects have a
    // hidden reference to the Microsoft.VisualBasic assembly
    bool referenceToMSVB = referencedAssemblies.Contains("Microsoft.VisualBasic");

    // VB.NET projects also typically reference the special
    // (YourProject).My.My* types that VB generates
    bool areMyTypesPresent = types.Select(x => x.FullName).Where(x => x.Contains(".My.My")).Any();

    // If a VB.NET project uses any anonymous types,
    // the compiler names them like VB$AnonymousType_0`1
    bool generatedVbNames = types.Select(x => x.Name).Where(x => x.StartsWith("VB$")).Any();

    // If a C# project uses dynamic, it'll have a reference to Microsoft.CSharp
    bool referenceToMSCS = referencedAssemblies.Contains("Microsoft.CSharp");

    // If a C# project uses any anonymous types,
    // the compiler names them like <>f__AnonymousType0`1
    bool generatedCsNames = types.Select(x => x.Name).Where(x => x.StartsWith("<>")).Any();

    var evidenceForVb = new bool[] 
    {
        referenceToMSVB,
        myTypesPresent,
        vbGeneratedNames
    };

    var evidenceForCsharp = new bool[] {
        true, // freebie. ensures ties go to C#
        referenceToMSCS,
        csGeneratedNames
    };

    var scoreForVb = evidenceForVb.Count(x => x)
                     - evidenceForCsharp.Count(x => x);

    // In the case of a tie, C# is assumed
    return scoreForVb > 0
        ? "vb"
        : "cs";
}
Run Code Online (Sandbox Code Playgroud)