Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I'm getting `System.InvalidOperationException: Collection was modified; enumeration operation may not execute`, inexplicably

I'm getting System.InvalidOperationException: Collection was modified; enumeration operation may not execute:

ExceptionLoggingLibrary.LoggingException: Exception of type 'ExceptionLoggingLibrary.LoggingException' was thrown. ---> System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at iTextSharp.text.FontFactoryImp.GetFont(String fontname, String encoding, Boolean embedded, Single size, Int32 style, BaseColor color, Boolean cached)
[...]

From what I understand, that exception happens when an IEnumerable object is modified during its enumeration.

Here's the iTextSharp.text.FontFactoryImp.GetFont method:

    public virtual Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color, bool cached) {
        if (fontname == null) return new Font(Font.FontFamily.UNDEFINED, size, style, color);
        string lowercasefontname = fontname.ToLower(CultureInfo.InvariantCulture);
        List<string> tmp;
        fontFamilies.TryGetValue(lowercasefontname, out tmp);
        if (tmp != null) {
            // some bugs were fixed here by Daniel Marczisovszky
            int fs = Font.NORMAL;
            bool found = false;
            int s = style == Font.UNDEFINED ? Font.NORMAL : style;
            foreach (string f in tmp) {
                string lcf = f.ToLower(CultureInfo.InvariantCulture);
                fs = Font.NORMAL;
                if (lcf.ToLower(CultureInfo.InvariantCulture).IndexOf("bold") != -1) fs |= Font.BOLD;
                if (lcf.ToLower(CultureInfo.InvariantCulture).IndexOf("italic") != -1 || lcf.ToLower(CultureInfo.InvariantCulture).IndexOf("oblique") != -1) fs |= Font.ITALIC;
                if ((s & Font.BOLDITALIC) == fs) {
                    fontname = f;
                    found = true;
                    break;
                }
            }
            if (style != Font.UNDEFINED && found) {
                style &= ~fs;
            }
        }
        BaseFont basefont = null;
        try {
            try {
                // the font is a type 1 font or CJK font
                basefont = BaseFont.CreateFont(fontname, encoding, embedded, cached, null, null, true);
            }
            catch (DocumentException) {
            }
            if (basefont == null) {
                // the font is a true type font or an unknown font
                trueTypeFonts.TryGetValue(fontname.ToLower(CultureInfo.InvariantCulture), out fontname);
                // the font is not registered as truetype font
                if (fontname == null) return new Font(Font.FontFamily.UNDEFINED, size, style, color);
                // the font is registered as truetype font
                basefont = BaseFont.CreateFont(fontname, encoding, embedded, cached, null, null);
            }
        }
        catch (DocumentException de) {
            // this shouldn't happen
            throw de;
        }
        catch (System.IO.IOException) {
            // the font is registered as a true type font, but the path was wrong
            return new Font(Font.FontFamily.UNDEFINED, size, style, color);
        }
        catch {
            // null was entered as fontname and/or encoding
            return new Font(Font.FontFamily.UNDEFINED, size, style, color);
        }
        return new Font(basefont, size, style, color);
    }

Where in that method is it possible that an IEnumerable object is being modified during enumeration?

like image 742
mattalxndr Avatar asked Apr 23 '13 18:04

mattalxndr


People also ask

What is InvalidOperationException in C#?

InvalidOperationException is used in cases when the failure to invoke a method is caused by reasons other than invalid arguments. Typically, it is thrown when the state of an object cannot support the method call. For example, an InvalidOperationException exception is thrown by methods such as: IEnumerator.


1 Answers

Without knowing what is inside your methods, this will prevent your Collection from being changed during enumeration:

Change:

List<string> tmp;
fontFamilies.TryGetValue(lowercasefontname, out tmp);

To:

List<string> sharedList;
fontFamilies.TryGetValue(lowercasefontname, out sharedList);
var tmp = new List<string>(sharedList);

This will give you a new list that you can be sure is not being accessed anywhere else by any other threads since it is guaranteed to not just be a reference to the list in TryGetValue().

I've changed the name of the tmp list from before and named the new list tmp so that you won't need to change any other code.

like image 146
Chris Avatar answered Oct 06 '22 23:10

Chris