7

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

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

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

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

Любые предложения?

Thanks,

Tim.

+0

Возможно, `[SecurityCritical]` пытается сказать вам, что вы не используете `var` и более специфичны для конкретного типа? – BeemerGuy 2010-11-25 14:24:03

ответ

3

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

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

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

3

У меня была такая же проблема, в сложном приложении. Весна приходит между ними и говорит, что тип «blahblah» не Serializable и, конечно же, это было правильно. Вот разобранный код сгенерированного кода компилятора и уверен, что это не Serializable. Возможно, это и ваша проблема, и решение - это то, о чем вы говорили сами, потому что List на самом деле является 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; 
     } 
    } 
} 
0

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

[EDIT] Ответ Microsoft:

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

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