Problem using C # iterator methods with code access protection

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; } } 

This method usually works fine, but if I apply the [SecurityCritical] attribute to the assembly (or to the class that contains the above method), it throws a TypeLoadException when trying to call the method. A type that does not load is a class generated by the compiler that matches the iterator method, and it is its GetEnumerator method that causes the problem because it is transparent to security.

For comparison, if I modify the above method to populate and return a List<MyItem> , everything will be fine.

Any suggestions?

Thanks,

Tim.

+7
iterator c # yield-return typeloadexception code-access-security
source share
3 answers

This is not the most difficult thing, so I hope you can find a better way, but you can always give up the code generated by the compiler and create your own class that implements IEnumerator<MyItem> (and possibly your own class that implements IEnumerable<MyItem> - depending on complexity, this can make things easier or more complicated), and then build a counter more or less, like in the days before .NET2.0.

If the logic of your real iterator block is very complex, you can find a reflection of the class created for you to be a good starting point for this, although sometimes the generated code is more complex (or at least less readable) than the approach that could to take.

It is always inconvenient to build the IEnumerator class when yield made it so enjoyable for us in 99% of cases, but there are still times when it is necessary, and this can solve your problem here.

+3
source share

I had the same problem in a complex application. Spring is in between and says the type 'blahblah' is not Serializable and is sure that he was right. Here is the parsed code of the generated compiler code and I'm sure that it is not Serializable. Perhaps this is both your problem and the solution is what you yourself were talking about, because List is actually a Serializable type.

The code generates for yield return new KeyValuePair<??? ???>(???,???); 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
source share

You can vote for this issue: https://connect.microsoft.com/VisualStudio/feedback/details/667328/yield-and-securitycriticalattribute-problem

[EDIT] Reply from Microsoft:

We looked at SecurityCritical iterators and decided not to try to do this work for at least this release. This is a significant and complex effort, and it does not seem too useful, since calling through IEnumerator.MoveNext will invoke a non-critical interface.

We will probably review this again in a later release; especially if we see common scenarios for him.

0
source share

All Articles