在IIS7下存在一个奇怪的64/32位GUID问题

11

我的团队最近在编程中遇到了一个有趣的问题,可能需要一些复杂的解释,请耐心听我讲述。我们正在开发一个ASP.Net应用程序,在其中使用了一个简单的"if"语句。

Guid adminId = Guid.Empty;
if (mRoles.Contains("Admin"))
{
    adminId = mUserId;
}

(其中mRoles是一个列表,包含“Admin”)

这个代码按预期工作(即将mUserId分配给adminID)。然而,当重写为在下面使用三元运算符时,它不起作用!(adminID被分配了空的Guid)!

Guid adminId = mRoles.Contains("Admin") ? mUserId : Guid.Empty;

这位开发者在64位机器(IIS7/64-bit vista)上发现了这个问题,如果他按照以下方式更改IIS设置...在"默认应用程序池(Default Application Pool)"下的"高级设置(Advanced Settings)"中勾选"启用32位应用程序"。现在两个语句都可以工作了!
我们认为这可能与Guid是一个结构体而不是类有关,值在64位进程下被偏移了。
我怀疑问题类似于这个... http://www.mail-archive.com/comtypes-users@lists.sourceforge.net/msg00164.html 这可能解释了为什么第一个简单的if语句可以工作。(因为创建adminId变量可能会创建一个指针,三元运算符不会?)
如果有人能解释一下这个问题就太好了。 这是兼容性错误吗?还是我们对三元运算符和结构体的组合理解有误?
谢谢。
更新
组合了一个简单的应用程序,在一个全新的项目中无法重现这个问题,所以必须是GUID之外的其他原因。
// 工作正常(将mUserId分配给adminId)
Guid adminId = true ? mUserId : Guid.Empty;

// 不起作用(即使t == true !!!!???)

bool t = (mRoles.Contains("TenantAdmin");
Guid adminId = t ? mUserId : Guid.Empty;

我认为我们需要重新开始思考这个问题。感谢大家的帮助,如果有进一步的消息,我会再次在这里发布。

唯一可能不太清楚的是mRoles不是一个类型为string的通用列表。它是一个string[],而Contains()方法是LINQ的扩展方法,如果有任何区别,但看不出来 :-?

更新2

我们已经查看了IL代码,并且是正确的(现在间歇性地工作!)。我们发现当默认应用程序池加载更多应用程序时,它开始再次失败。我们能想到的唯一其他事情是,一些其他应用程序可能包含一些非托管代码,这些代码某种方式干扰了我们的应用程序,这可能是可能的吗?


2
你能否在一个全新的项目中用几行简单的代码复制这种行为? - Noon Silk
1
在编译期间不同设置生效时,比较生成的IL。 - AakashM
是的,我们可以复现它,如果在IIS中切换“启用32位应用程序”,它会停止/开始工作。奇怪的。 - ChrisV
好的。我会在今天某个时候完成并查看IL。 - ChrisV
为了验证这一点,需要重新创建一个与您的其余代码无关的独立应用程序(例如,不是mRoles有所不同)。考虑控制台应用程序。 - Richard
显示剩余4条评论
6个回答

1
请尝试在三元运算符周围加上括号,如果您还没有这样做的话。
我们曾经遇到过类似的问题,其中代码与您的相似:
Guid adminId = t ? mUserId : Guid.Empty;

编译顺序错误:

(Guid adminId = t) ? mUserId : Guid.Empty;

添加括号以指定顺序即可解决:

Guid adminId = (t ? mUserId : Guid.Empty);

我通过使用 .NET Reflector 查看编译后的代码弄清楚了它在做什么。


0

也许明确告诉赋值运算符三元运算符的返回值是Guid会有所帮助?

Guid adminId = (Guid)(mRoles.Contains("Admin") ? mUserId : Guid.Empty);

只是一个猜测...


类似的猜测——这是否是评估顺序呢?尝试在三元语句周围加上括号,以确保你不会将赋值解析为条件。 - mpez0

0
你尝试过以下方法吗:
Guid adminId = mRoles.Contains("Admin") ? (Guid)mUserId : Guid.Empty;

只是好奇,如果由于某种原因,在64位操作系统下,mUserId被内部识别为不同的类型,那么显式转换是否有帮助。以下也可能是一个选项:

Guid adminId = mRoles.Contains("Admin") ? new Guid(mUserId.ToByteArray()) : Guid.Empty;

0

想知道64位机器认为mUserId是什么类型?大概不是Guid吧。


如果mUserId不是GUID,你会得到一个编译器错误,指出无法确定返回类型。 - Mark

0

我不确定,但是我认为在使用三元操作时,两个分支都必须被执行,然而使用GUID可能会导致两个GUID以某种方式被评估。


0

这似乎是IIS中的一个错误,以及在同一应用程序池中运行的另一个应用程序中的一块非托管代码。我们已经暂时解决了这个问题,并将通过我们的合作关系向Microsoft提出。当它得到解决后,我会在这里回复让您知道。

感谢大家的帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接