Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem using C# iterator methods with code access security

I have a simple method that uses an iterator block to return an IEnumerable<T>:

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

Ordinarily, this method works fine, but if I apply a [SecurityCritical] attribute to the assembly (or to the class that contains the above method), it throws a TypeLoadException when attempting to invoke the method. The type that is failing to load is the compiler-generated class that corresponds to the iterator method, and it is its GetEnumerator method that is causing the problem, since it is security transparent.

For comparison, if I modify the above method so that it populates and returns a List<MyItem>, everything works fine.

Any suggestions?

Thanks,

Tim.

like image 757
Tim Coulter Avatar asked Nov 25 '10 14:11

Tim Coulter


2 Answers

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.

like image 179
Jon Hanna Avatar answered Oct 09 '22 20:10

Jon Hanna


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;
        }
    }
}
like image 37
Jahan Zinedine Avatar answered Oct 09 '22 20:10

Jahan Zinedine