如何找到public extern bool Equals(String value)的实现代码?[C#, C++, BCL, CLR]

本文详细解析了如何在Rotor源代码中找到String.Equals(String value)的实现细节,从extern声明到C++底层实现,包括宏定义、方法映射及字符串比较算法。

如何找到public extern bool Equals(String value)的实现代码?[C#, C++, BCL, CLR]

 

Written by Allen Lee

 

Q:在微软提供的Rotor源代码中,我发现String.Equals(String value)的代码只有下面两行:

None.gif //  Code #01
None.gif
[MethodImplAttribute(MethodImplOptions.InternalCall)]
None.gif
public   extern   bool  Equals(String value);

那么,在哪里可以找到该方法的实现代码呢?

A:打开Rotor源代码的sscli\clr\src\vm\ecall.cpp文件,搜索“Equals”关键字,你将找到如下所示的数组成员:

None.gif //  Code #02
ExpandedBlockStart.gifContractedBlock.gif
static  ECFunc gStringFuncs[]  =   dot.gif {
InBlock.gif
InBlock.gif    
// Other members heredot.gif
InBlock.gif

ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{FCFuncElement("Equals"&gsig_IM_Str_RetBool, (LPVOID)COMString::EqualsString)},
InBlock.gif
InBlock.gif    
// Other members heredot.gif
ExpandedBlockEnd.gif
}
;

从该数组成员中,我们可以得知我们要寻找的就是COMString::EqualsString函数。那么,ComString::EqualsString函数的实现代码又在哪里呢?

打开Rotor源代码的sscli\clr\src\vm\comstring.cpp文件,搜索“COMString::EqualsString”关键字,怎么样,找到实现代码了吗?


Q:是的,我找到了:

None.gif //  Code #03
None.gif
FCIMPL2(INT32, COMString::EqualsString, StringObject *  thisStr, StringObject *  valueStr) 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    VALIDATEOBJECTREF(thisStr);
InBlock.gif    VALIDATEOBJECTREF(valueStr);
InBlock.gif
InBlock.gif    INT32 ret 
= false;
InBlock.gif    
if (NULL==thisStr)
InBlock.gif        FCThrow(kNullReferenceException);
InBlock.gif        
InBlock.gif    
if (!valueStr)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        FC_GC_POLL_RET();
InBlock.gif        
return ret;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    ret 
= WcharCompareHelper (STRINGREF(thisStr), STRINGREF(valueStr));
InBlock.gif    FC_GC_POLL_RET();
InBlock.gif    
return ret;
ExpandedBlockEnd.gif}

None.gifFCIMPLEND

你能否简单说明一下?

A:Code #03的函数的定义使用了宏(Macro)。在sscli\clr\src\vm\fcall.h文件中,你会找到如下语句:

None.gif //  Code #04
None.gif
#define  FCDECL2(rettype, funcname, a1, a2) rettype F_CALL_CONV funcname(a1, a2)

这就是该函数的宏定义。于是,上面你所找到的C++代码就可以展开为:

None.gif //  Code #05
None.gif
INT32 F_CALL_CONV COMString::EqualsString(StringObject *  thisStr, StringObject *  valueStr)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
// dot.gif
ExpandedBlockEnd.gif
}

Code #04所示的宏是对应着x86体系的,对于非x86体系,该函数的宏定义为:

None.gif //  Code #06
None.gif
#define  FCIMPL2(rettype, funcname, a1, a2) rettype funcname(a1, a2) { FCIMPL_PROLOG(funcname)

另外,该函数其实把真正的比较工作交给了WcharCompareHelper函数,你可以在同一个文件(comstring.cpp)中找到它的真身:

None.gif //  Code #07
None.gif
bool  WcharCompareHelper (STRINGREF thisStr, STRINGREF valueStr)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    DWORD 
*thisChars, *valueChars;
InBlock.gif    
int thisLength, valueLength;
InBlock.gif
InBlock.gif    
//Get all of our required data.
InBlock.gif
    RefInterpretGetStringValuesDangerousForGC(thisStr, (WCHAR**)&thisChars, &thisLength);
InBlock.gif    RefInterpretGetStringValuesDangerousForGC(valueStr, (WCHAR
**)&valueChars, &valueLength);
InBlock.gif
InBlock.gif    
//If they're different lengths, they're not an exact match.
ExpandedSubBlockStart.gifContractedSubBlock.gif
    if (thisLength!=valueLength) dot.gif{
InBlock.gif        
return false;
ExpandedSubBlockEnd.gif    }

InBlock.gif  
InBlock.gif    
// Loop comparing a DWORD (2 WCHARs) at a time.
InBlock.gif
    while ((thisLength -= 2>= 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
if (*thisChars != *valueChars)
InBlock.gif            
return false;
InBlock.gif        
++thisChars;
InBlock.gif        
++valueChars;
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
// Handle an extra WCHAR.
InBlock.gif
    if (thisLength == -1)
InBlock.gif        
return (*((WCHAR *) thisChars) == *((WCHAR *) valueChars));
InBlock.gif
InBlock.gif    
return true;
ExpandedBlockEnd.gif}

至此,你已经找到Rotor的String.Equals(String value)的实现算法了。


Q:ecall.cpp文件是用来干什么的?

A:该文件包含着为数众多的数组,这些数组实质上充当一个表的角色,用于把标记了[MethodImplAttribute(MethodImplOptions.InternalCall)]属性的方法映射为非托管的C++实现。其中,数组的成员实际上也使用了宏。Code #02中的

None.gif //  Code #08
None.gif
FCFuncElement( " Equals " & gsig_IM_Str_RetBool, (LPVOID)COMString::EqualsString)

就对应着Code #09的宏定义:

None.gif //  Code #09
None.gif
#define  FCFuncElement(A,B,C) A, B, C, NULL, CORINFO_INTRINSIC_Illegal


Q:fcall.h文件又是用来干什么的?

A:该文件也定义了为数众多的宏,这些宏充当着“函数模板”的角色,用于把签名相类似的函数组织起来,并以统一的方式展开。该文件开头还留有相关的注释,用于说明这些宏的作用、工作原理以及相关注意事项。


Q:什么情况下,我们可以使用这种方法来查找Rotor BCL中没有给出具体实现的方法代码?

A:我们知道,没有给出具体实现代码的方法,需要添加extern以表明该实现在别的某处可以找到,一般情况下,该修饰符与DllImportAttribute结合使用:

None.gif //  Code #10
None.gif
[DllImport( " uxtheme.dll " )]
None.gif
static   public   extern   int  SetWindowTheme(IntPtr hWnd, StringBuilder AppID, StringBuilder ClassID);
None.gif
static   public   void  DisableWindowsXPTheme(IntPtr hWnd) 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
// Disable using the Window XP Theme for the Window handle
InBlock.gif    
// passed as a parameter
InBlock.gif
    StringBuilder applicationName = new StringBuilder(" "1); 
InBlock.gif    StringBuilder classIDs 
= new StringBuilder(" " , 1); 
InBlock.gif    Win32.SetWindowTheme(hWnd, applicationName, classIDs);
ExpandedBlockEnd.gif}

这样,.NET就会自动从uxtheme.dll那里寻找对应的实现代码,这种调用方式叫做PInvoke。当然,这种情况下,你是无法获取具体的实现代码了。

然而,BCL中有相当一部分方法使用extern和MethodImplAttribute来修饰的,此时,只要给MethodImplAttribute的构造函数传递的参数是MethodImplOptions.InternalCall枚举,就代表着你可以使用我介绍给你的方法来寻找实现代码了。底线是你拥有这些底层非托管源代码让你寻找!


Q:MethodImplAttribute用来干什么的?

A:该Attribute位于System.Runtime.CompilerServices命名空间,结合MethodImplOptions枚举来使用,用于描述方法或者构造器的实现方式。Code #01中的[MethodImplAttribute(MethodImplOptions.InternalCall)]则用于说明该方法的具体实现可以从CLR内部找到。该属性实质上是一种伪属性(pseudo-attribute),有别于普通的自定义属性,它是以位的形式储存在元数据表(metadata table)中的,并且只能通过MethodBase.GetMethodImplementationFlags来获取相关的信息。


Q:从上面的讨论,我们可以了解到EqualsString函数是属于一个叫ComString的类,那么这个ComString类与BCL中的String类有什么关系?

A:Good question!Rotor BCL中的String.cs中我们可以找到这样一句话:

Actual implementations are in String.cpp

事实上,这个String.cpp就是comstring.cpp;同样,在comstring.cpp中,我们也可以看到这样一句话:

Purpose: The implementation of the String class.

我们发现String.cs中很多方法都没有提供具体的实现代码,而这些方法的真身其实就隐藏在comstring.cpp中。


Q:最后,对于探索.NET内部原理,你有什么好推荐?

A:其实微软所提供的Rotor源代码以及Mono这个开源项目里面已经有很丰富的注释以供学习之用。当然,我还是要为大家介绍几个有用的连接:

希望这些资料能够帮助大家更好的探索.NET的内部原理。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值