問題描述
使用具有代碼訪問安全性的 C# 迭代器方法時出現問題 (Problem using C# iterator methods with code access security)
我有一個使用迭代器塊返回 IEnumerable
的簡單方法:
IEnumerable<MyItem> GetItems()
{
foreach (var item in Items)
{
yield return item;
}
}
通常,此方法可以正常工作,但如果我將 [SecurityCritical]
屬性應用於程序集(或包含上述方法的類),則會引發 TypeLoadException 嘗試調用該方法時。加載失敗的類型是編譯器生成的與迭代器方法相對應的類,它的
GetEnumerator
方法導致了問題,因為它是安全透明的。
< p>為了比較,如果我修改上述方法,使其填充並返回一個 List
,一切正常。 有什麼建議嗎?
謝謝,
蒂姆。
參考解法
方法 1:
It isn't the neatest thing to do, so hopefully you can find a better way, but you could always forgo the compiler‑generated code and create your own class that implements IEnumerator<MyItem>
(and perhaps your own class implementing IEnumerable<MyItem>
‑ depending on complexity, doing so may make things easier or more difficult), and then build the enumerator more or less as you would in the days before .NET2.0.
If the logic of your real iterator block is very complicated, you might find looking at the reflection of the class the compiler created for you to be a good starting point in doing this, though sometimes the generated code is more complicated (or at least, less readable) than the approach one would take oneself.
It's always a bit disappointing to have to build an IEnumerator
class when yield
has made it so nice for us 99% of the time, but there are still times when its necessary, and it might solve your problem here.
方法 2:
I had the very same problem, in a complicated application. Spring comes in between and said that the 'blahblah' type is not Serializable
and sure it was correct, Here is the disassembled code of compiler generated code and sure it's not Serializable. Maybe this was your problem too, and the solution is what you mentioned yourself cause the List is actually a Serializable type.
The code generate for yield return new KeyValuePair<??? ???>(???,???);
[CompilerGenerated, DebuggerDisplay(@"\{ x = {x}, y = {y} }", Type="<Anonymous Type>")]
internal sealed class <>f__AnonymousType0<<x>j__TPar, <y>j__TPar>
{
// Fields
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly <x>j__TPar <x>i__Field;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly <y>j__TPar <y>i__Field;
// Methods
[DebuggerHidden]
public <>f__AnonymousType0(<x>j__TPar x, <y>j__TPar y)
{
this.<x>i__Field = x;
this.<y>i__Field = y;
}
[DebuggerHidden]
public override bool Equals(object value)
{
var type = value as <>f__AnonymousType0<<x>j__TPar, <y>j__TPar>;
return (((type != null) && EqualityComparer<<x>j__TPar>.Default.Equals(this.<x>i__Field, type.<x>i__Field)) && EqualityComparer<<y>j__TPar>.Default.Equals(this.<y>i__Field, type.<y>i__Field));
}
[DebuggerHidden]
public override int GetHashCode()
{
int num = ‑576933007;
num = (‑1521134295 * num) + EqualityComparer<<x>j__TPar>.Default.GetHashCode(this.<x>i__Field);
return ((‑1521134295 * num) + EqualityComparer<<y>j__TPar>.Default.GetHashCode(this.<y>i__Field));
}
[DebuggerHidden]
public override string ToString()
{
StringBuilder builder = new StringBuilder();
builder.Append("{ x = ");
builder.Append(this.<x>i__Field);
builder.Append(", y = ");
builder.Append(this.<y>i__Field);
builder.Append(" }");
return builder.ToString();
}
// Properties
public <x>j__TPar x
{
get
{
return this.<x>i__Field;
}
}
public <y>j__TPar y
{
get
{
return this.<y>i__Field;
}
}
}
方法 3:
You can vote for this issue: https://connect.microsoft.com/VisualStudio/feedback/details/667328/yield‑and‑securitycriticalattribute‑problem
[EDIT] Response from Microsoft:
We've looked at SecurityCritical iterators and decided not to try to make that work at least for this release. It is a significant and complicated effort, and it does not seem too useful, as the call through IEnumerator.MoveNext would be calling through a non‑critical interface.
We'll probably revisit this again in a later release; especially if we see common scenarios for it.
(by Tim Coulter、Jon Hanna、Jahan Zinedine、QrystaL)
參考文件