Проблема с использованием методов итератора C # с безопасностью доступа к коду - PullRequest
7 голосов
/ 25 ноября 2010

У меня есть простой метод, который использует блок итератора для возврата IEnumerable<T>:

IEnumerable<MyItem> GetItems()
{
    foreach (var item in Items)
    {
        yield return item;
    }
}

Обычно этот метод работает нормально, но если я применяю атрибут [SecurityCritical] к сборке (или к классу, который содержит вышеупомянутый метод), он выдает TypeLoadException при попытке вызвать метод. Тип, который не удается загрузить, - это класс, сгенерированный компилятором, который соответствует методу итератора, и именно его GetEnumerator метод вызывает проблему, поскольку он прозрачен для безопасности.

Для сравнения, если я изменю приведенный выше метод так, чтобы он заполнял и возвращал List<MyItem>, все работает нормально.

Есть предложения?

Спасибо

Тим.

Ответы [ 3 ]

3 голосов
/ 04 декабря 2010

У меня была та же проблема, в сложном приложении. Между ними появляется Spring и говорит, что тип 'blahblah' не Serializable и уверен, что он был правильным. Вот дизассемблированный код кода, сгенерированного компилятором, и уверен, что он не сериализуем. Возможно, это и была ваша проблема, и решение - то, что вы упомянули сами, потому что список на самом деле является сериализуемым типом.

Код, сгенерированный для 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 голосов
/ 30 ноября 2010

Это не самая лучшая вещь, так что, надеюсь, вы сможете найти лучший способ, но вы всегда можете отказаться от сгенерированного компилятором кода и создать свой собственный класс, который реализует IEnumerator<MyItem> (и, возможно, ваш собственный класс, реализующий IEnumerable<MyItem> - в зависимости от сложности, это может сделать вещи проще или сложнее), а затем построить счетчик более или менее, как это было бы в дни до .NET2.0.

Если логика вашего реальногоБлок итератора очень сложен, вы можете найти, что представление класса, созданного компилятором для вас, является хорошей отправной точкой в ​​этом, хотя иногда сгенерированный код является более сложным (или, по крайней мере, менее читабельным), чем подходкаждый взял бы себя.

Всегда немного разочаровывает необходимость создавать класс IEnumerator, когда yield делает его таким приятным для нас в 99% случаев, но бывают моменты, когда это необходимои это может решить вашу проблему здесь.

0 голосов
/ 10 мая 2011

Вы можете проголосовать за эту проблему: https://connect.microsoft.com/VisualStudio/feedback/details/667328/yield-and-securitycriticalattribute-problem

[ПРАВИТЬ] Ответ от Microsoft:

Мы рассмотрели итераторы SecurityCritical и решили не пытаться сделать этоработать по крайней мере для этого выпуска.Это значительное и сложное усилие, и оно не кажется слишком полезным, поскольку вызов через IEnumerator.MoveNext будет вызывать через некритический интерфейс.

Вероятно, мы еще вернемся к этому вопросу в следующем выпуске;особенно если мы видим общие сценарии для этого.

...