使用具有代碼訪問安全性的 C# 迭代器方法時出現問題 (Problem using C# iterator methods with code access security)


問題描述

使用具有代碼訪問安全性的 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 CoulterJon HannaJahan ZinedineQrystaL)

參考文件

  1. Problem using C# iterator methods with code access security (CC BY‑SA 3.0/4.0)

#yield-return #typeloadexception #iterator #code-access-security #C#






相關問題

Bagaimana saya bisa membuat `menunggu ...` bekerja dengan `yield return` (yaitu di dalam metode iterator)? (How can I make `await …` work with `yield return` (i.e. inside an iterator method)?)

收益回報使用 (yield return usage)

無法將“<>d__6”類型的對象轉換為“System.Object[]”類型 (Unable to cast object of type '<>d__6' to type 'System.Object[]')

使用 yield return 時 GetEnumerator() 方法會發生什麼? (What happens to GetEnumerator() method when yield return is used?)

抓取回調函數 (Scrapy callback function)

我可以在 VB.NET 中為 IEnumerable 函數實現收益返回嗎? (Can I implement yield return for IEnumerable functions in VB.NET?)

使用具有代碼訪問安全性的 C# 迭代器方法時出現問題 (Problem using C# iterator methods with code access security)

如何使用收益返回和遞歸獲得每個字母組合? (How do I get every combination of letters using yield return and recursion?)

是否可以使用 'yield' 來生成 'Iterator' 而不是 Scala 中的列表? (Is it possible to use 'yield' to generate 'Iterator' instead of a list in Scala?)

yield return 除了 IEnumerable 之外還有其他用途嗎? (Does yield return have any uses other than for IEnumerable?)

這個函數可以用更有效的方式編寫嗎? (Can this function be written in more efficient way?)

當我在代碼中引入產量時,它在 python 中不起作用 (when i introduced yield in code it doesn't work in python)







留言討論