ib11
ib11

Reputation: 2568

C# speed up slow loop in accessing Word.Languages

I am working on automating Word via Office.Interop as part of a C# plugin.

I have a loop in my C# code that has only one function is to look up a string of a language's name in the collection of Word.Languages and then once I have the ID for that language, I then assign it to the selection. Here is the code:

using Word = Microsoft.Office.Interop.Word;

Word.Application oWord = new Word.Application();
Word.Document oWordDoc = new Word.Document();

//Opening document here and doing stuff with it

var Selection = oWordDoc.ActiveWindow.Selection;

string strTgtLanguage="Hungarian";

var test = oWord.Application.Languages;
foreach (Word.Language item in test)
{
    if (item.NameLocal.IndexOf(strTgtLanguage) > -1)
    {
        Selection.LanguageID = item.ID;
        break;
    }
}

It takes about 1 second per language to do the lookup. With over 250 items in the collection I am looking at 4 minutes for Xhosa and Zulu.

So I am trying to speed this up. As in the code, I apparently managed to gain some speed on assigning the collection to an object and doing the loop on that object, but it still in the same order of magnitude.

I have been researching some options on SO and otherwise, but I did not find any so far that would fit this specific situation. Maybe a LINQ query would be faster?

I wonder if somebody could help with this. Thanks.

Update

I was experimenting based on the answers and tried to make List:

        private class LanguageItem
    {
        public Word.WdLanguageID Id { get; set; }
        public string Name { get; set; }

        public LanguageItem(string name, int id)
        {
            Id = (Word.WdLanguageID)id;
            Name = name;
        }
    }

    public static class LanguageList
    {            
        private List<LanguageItem> _languageList;

        private LanguageList()
        {
            _languageList.Add(new LanguageItem("Arabic", 1025));
            _languageList.Add(new LanguageItem("Bulgarian", 1026));
            _languageList.Add(new LanguageItem("Catalan", 1027));
            _languageList.Add(new LanguageItem("TraditionalChinese", 1028));
            _languageList.Add(new LanguageItem("Czech", 1029));
            _languageList.Add(new LanguageItem("Danish", 1030));
            _languageList.Add(new LanguageItem("German", 1031));
            _languageList.Add(new LanguageItem("Greek", 1032));
            _languageList.Add(new LanguageItem("EnglishUS", 1033));
            _languageList.Add(new LanguageItem("Spanish", 1034));
            _languageList.Add(new LanguageItem("Finnish", 1035));
            _languageList.Add(new LanguageItem("French", 1036));
            _languageList.Add(new LanguageItem("Hebrew", 1037));
            _languageList.Add(new LanguageItem("Hungarian", 1038));
            _languageList.Add(new LanguageItem("Icelandic", 1039));
            _languageList.Add(new LanguageItem("Italian", 1040));
            _languageList.Add(new LanguageItem("Japanese", 1041));
            _languageList.Add(new LanguageItem("Korean", 1042));
            _languageList.Add(new LanguageItem("Dutch", 1043));
            _languageList.Add(new LanguageItem("NorwegianBokmol", 1044));
            _languageList.Add(new LanguageItem("Polish", 1045));
            _languageList.Add(new LanguageItem("BrazilianPortuguese", 1046));
            _languageList.Add(new LanguageItem("RhaetoRomanic", 1047));
            _languageList.Add(new LanguageItem("Romanian", 1048));
            _languageList.Add(new LanguageItem("Russian", 1049));
            _languageList.Add(new LanguageItem("Croatian", 1050));
            _languageList.Add(new LanguageItem("Slovak", 1051));
            _languageList.Add(new LanguageItem("Albanian", 1052));
            _languageList.Add(new LanguageItem("Swedish", 1053));
            _languageList.Add(new LanguageItem("Thai", 1054));
            _languageList.Add(new LanguageItem("Turkish", 1055));
            _languageList.Add(new LanguageItem("Urdu", 1056));
            _languageList.Add(new LanguageItem("Indonesian", 1057));
            _languageList.Add(new LanguageItem("Ukrainian", 1058));
            _languageList.Add(new LanguageItem("Byelorussian", 1059));
            _languageList.Add(new LanguageItem("Slovenian", 1060));
            _languageList.Add(new LanguageItem("Estonian", 1061));
            _languageList.Add(new LanguageItem("Latvian", 1062));
            _languageList.Add(new LanguageItem("Lithuanian", 1063));
            _languageList.Add(new LanguageItem("Tajik", 1064));
            _languageList.Add(new LanguageItem("Farsi", 1065));
            _languageList.Add(new LanguageItem("Vietnamese", 1066));
            _languageList.Add(new LanguageItem("Armenian", 1067));
            _languageList.Add(new LanguageItem("AzeriLatin", 1068));
            _languageList.Add(new LanguageItem("Basque", 1069));
            _languageList.Add(new LanguageItem("Sorbian", 1070));
            _languageList.Add(new LanguageItem("Macedonian", 1071));
            _languageList.Add(new LanguageItem("Sesotho", 1072));
            _languageList.Add(new LanguageItem("Sutu", 1072));
            _languageList.Add(new LanguageItem("Tsonga", 1073));
            _languageList.Add(new LanguageItem("Tswana", 1074));
            _languageList.Add(new LanguageItem("Venda", 1075));
            _languageList.Add(new LanguageItem("Xhosa", 1076));
            _languageList.Add(new LanguageItem("Zulu", 1077));
            _languageList.Add(new LanguageItem("Afrikaans", 1078));
            _languageList.Add(new LanguageItem("Georgian", 1079));
            _languageList.Add(new LanguageItem("Faeroese", 1080));
            _languageList.Add(new LanguageItem("Hindi", 1081));
            _languageList.Add(new LanguageItem("Maltese", 1082));
            _languageList.Add(new LanguageItem("SamiLappish", 1083));
            _languageList.Add(new LanguageItem("GaelicScotland", 1084));
            _languageList.Add(new LanguageItem("Yiddish", 1085));
            _languageList.Add(new LanguageItem("Malaysian", 1086));
            _languageList.Add(new LanguageItem("Kazakh", 1087));
            _languageList.Add(new LanguageItem("Kirghiz", 1088));
            _languageList.Add(new LanguageItem("Kyrgyz", 1088));
            _languageList.Add(new LanguageItem("Swahili", 1089));
            _languageList.Add(new LanguageItem("Turkmen", 1090));
            _languageList.Add(new LanguageItem("UzbekLatin", 1091));
            _languageList.Add(new LanguageItem("Tatar", 1092));
            _languageList.Add(new LanguageItem("Bengali", 1093));
            _languageList.Add(new LanguageItem("Punjabi", 1094));
            _languageList.Add(new LanguageItem("Gujarati", 1095));
            _languageList.Add(new LanguageItem("Oriya", 1096));
            _languageList.Add(new LanguageItem("Tamil", 1097));
            _languageList.Add(new LanguageItem("Telugu", 1098));
            _languageList.Add(new LanguageItem("Kannada", 1099));
            _languageList.Add(new LanguageItem("Malayalam", 1100));
            _languageList.Add(new LanguageItem("Assamese", 1101));
            _languageList.Add(new LanguageItem("Marathi", 1102));
            _languageList.Add(new LanguageItem("Sanskrit", 1103));
            _languageList.Add(new LanguageItem("Mongolian", 1104));
            _languageList.Add(new LanguageItem("Tibetan", 1105));
            _languageList.Add(new LanguageItem("Welsh", 1106));
            _languageList.Add(new LanguageItem("Khmer", 1107));
            _languageList.Add(new LanguageItem("Lao", 1108));
            _languageList.Add(new LanguageItem("Burmese", 1109));
            _languageList.Add(new LanguageItem("Galician", 1110));
            _languageList.Add(new LanguageItem("Konkani", 1111));
            _languageList.Add(new LanguageItem("Manipuri", 1112));
            _languageList.Add(new LanguageItem("Sindhi", 1113));
            _languageList.Add(new LanguageItem("Syriac", 1114));
            _languageList.Add(new LanguageItem("Sinhalese", 1115));
            _languageList.Add(new LanguageItem("Cherokee", 1116));
            _languageList.Add(new LanguageItem("Inuktitut", 1117));
            _languageList.Add(new LanguageItem("Amharic", 1118));
            _languageList.Add(new LanguageItem("Tamazight", 1119));
            _languageList.Add(new LanguageItem("Kashmiri", 1120));
            _languageList.Add(new LanguageItem("Nepali", 1121));
            _languageList.Add(new LanguageItem("FrisianNetherlands", 1122));
            _languageList.Add(new LanguageItem("Pashto", 1123));
            _languageList.Add(new LanguageItem("Filipino", 1124));
            _languageList.Add(new LanguageItem("Divehi", 1125));
            _languageList.Add(new LanguageItem("Edo", 1126));
            _languageList.Add(new LanguageItem("Fulfulde", 1127));
            _languageList.Add(new LanguageItem("Hausa", 1128));
            _languageList.Add(new LanguageItem("Ibibio", 1129));
            _languageList.Add(new LanguageItem("Yoruba", 1130));
            _languageList.Add(new LanguageItem("Igbo", 1136));
            _languageList.Add(new LanguageItem("Kanuri", 1137));
            _languageList.Add(new LanguageItem("Oromo", 1138));
            _languageList.Add(new LanguageItem("TigrignaEthiopic", 1139));
            _languageList.Add(new LanguageItem("Guarani", 1140));
            _languageList.Add(new LanguageItem("Hawaiian", 1141));
            _languageList.Add(new LanguageItem("Latin", 1142));
            _languageList.Add(new LanguageItem("Somali", 1143));
            _languageList.Add(new LanguageItem("Yi", 1144));
            _languageList.Add(new LanguageItem("ArabicIraq", 2049));
            _languageList.Add(new LanguageItem("SimplifiedChinese", 2052));
            _languageList.Add(new LanguageItem("SwissGerman", 2055));
            _languageList.Add(new LanguageItem("EnglishUK", 2057));
            _languageList.Add(new LanguageItem("MexicanSpanish", 2058));
            _languageList.Add(new LanguageItem("BelgianFrench", 2060));
            _languageList.Add(new LanguageItem("SwissItalian", 2064));
            _languageList.Add(new LanguageItem("BelgianDutch", 2067));
            _languageList.Add(new LanguageItem("NorwegianNynorsk", 2068));
            _languageList.Add(new LanguageItem("Portuguese", 2070));
            _languageList.Add(new LanguageItem("RomanianMoldova", 2072));
            _languageList.Add(new LanguageItem("RussianMoldova", 2073));
            _languageList.Add(new LanguageItem("SerbianLatin", 2074));
            _languageList.Add(new LanguageItem("SwedishFinland", 2077));
            _languageList.Add(new LanguageItem("AzeriCyrillic", 2092));
            _languageList.Add(new LanguageItem("GaelicIreland", 2108));
            _languageList.Add(new LanguageItem("MalayBruneiDarussalam", 2110));
            _languageList.Add(new LanguageItem("UzbekCyrillic", 2115));
            _languageList.Add(new LanguageItem("DzongkhaBhutan", 2129));
            _languageList.Add(new LanguageItem("SindhiPakistan", 2137));
            _languageList.Add(new LanguageItem("TamazightLatin", 2143));
            _languageList.Add(new LanguageItem("TigrignaEritrea", 2163));
            _languageList.Add(new LanguageItem("ArabicEgypt", 3073));
            _languageList.Add(new LanguageItem("ChineseHongKongSAR", 3076));
            _languageList.Add(new LanguageItem("GermanAustria", 3079));
            _languageList.Add(new LanguageItem("EnglishAUS", 3081));
            _languageList.Add(new LanguageItem("SpanishModernSort", 3082));
            _languageList.Add(new LanguageItem("FrenchCanadian", 3084));
            _languageList.Add(new LanguageItem("SerbianCyrillic", 3098));
            _languageList.Add(new LanguageItem("ArabicLibya", 4097));
            _languageList.Add(new LanguageItem("ChineseSingapore", 4100));
            _languageList.Add(new LanguageItem("GermanLuxembourg", 4103));
            _languageList.Add(new LanguageItem("EnglishCanadian", 4105));
            _languageList.Add(new LanguageItem("SpanishGuatemala", 4106));
            _languageList.Add(new LanguageItem("SwissFrench", 4108));
            _languageList.Add(new LanguageItem("ArabicAlgeria", 5121));
            _languageList.Add(new LanguageItem("ChineseMacaoSAR", 5124));
            _languageList.Add(new LanguageItem("GermanLiechtenstein", 5127));
            _languageList.Add(new LanguageItem("EnglishNewZealand", 5129));
            _languageList.Add(new LanguageItem("SpanishCostaRica", 5130));
            _languageList.Add(new LanguageItem("FrenchLuxembourg", 5132));
            _languageList.Add(new LanguageItem("ArabicMorocco", 6145));
            _languageList.Add(new LanguageItem("EnglishIreland", 6153));
            _languageList.Add(new LanguageItem("SpanishPanama", 6154));
            _languageList.Add(new LanguageItem("FrenchMonaco", 6156));
            _languageList.Add(new LanguageItem("ArabicTunisia", 7169));
            _languageList.Add(new LanguageItem("EnglishSouthAfrica", 7177));
            _languageList.Add(new LanguageItem("SpanishDominicanRepublic", 7178));
            _languageList.Add(new LanguageItem("FrenchWestIndies", 7180));
            _languageList.Add(new LanguageItem("ArabicOman", 8193));
            _languageList.Add(new LanguageItem("EnglishJamaica", 8201));
            _languageList.Add(new LanguageItem("SpanishVenezuela", 8202));
            _languageList.Add(new LanguageItem("FrenchReunion", 8204));
            _languageList.Add(new LanguageItem("ArabicYemen", 9217));
            _languageList.Add(new LanguageItem("EnglishCaribbean", 9225));
            _languageList.Add(new LanguageItem("SpanishColombia", 9226));
            _languageList.Add(new LanguageItem("FrenchZaire", 9228));
            _languageList.Add(new LanguageItem("ArabicSyria", 10241));
            _languageList.Add(new LanguageItem("EnglishBelize", 10249));
            _languageList.Add(new LanguageItem("SpanishPeru", 10250));
            _languageList.Add(new LanguageItem("FrenchSenegal", 10252));
            _languageList.Add(new LanguageItem("ArabicJordan", 11265));
            _languageList.Add(new LanguageItem("EnglishTrinidadTobago", 11273));
            _languageList.Add(new LanguageItem("SpanishArgentina", 11274));
            _languageList.Add(new LanguageItem("FrenchCameroon", 11276));
            _languageList.Add(new LanguageItem("ArabicLebanon", 12289));
            _languageList.Add(new LanguageItem("EnglishZimbabwe", 12297));
            _languageList.Add(new LanguageItem("SpanishEcuador", 12298));
            _languageList.Add(new LanguageItem("FrenchCotedIvoire", 12300));
            _languageList.Add(new LanguageItem("ArabicKuwait", 13313));
            _languageList.Add(new LanguageItem("EnglishPhilippines", 13321));
            _languageList.Add(new LanguageItem("SpanishChile", 13322));
            _languageList.Add(new LanguageItem("FrenchMali", 13324));
            _languageList.Add(new LanguageItem("ArabicUAE", 14337));
            _languageList.Add(new LanguageItem("EnglishIndonesia", 14345));
            _languageList.Add(new LanguageItem("SpanishUruguay", 14346));
            _languageList.Add(new LanguageItem("FrenchMorocco", 14348));
            _languageList.Add(new LanguageItem("ArabicBahrain", 15361));
            _languageList.Add(new LanguageItem("SpanishParaguay", 15370));
            _languageList.Add(new LanguageItem("FrenchHaiti", 15372));
            _languageList.Add(new LanguageItem("ArabicQatar", 16385));
            _languageList.Add(new LanguageItem("SpanishBolivia", 16394));
            _languageList.Add(new LanguageItem("SpanishElSalvador", 17418));
            _languageList.Add(new LanguageItem("SpanishHonduras", 18442));
            _languageList.Add(new LanguageItem("SpanishNicaragua", 19466));
            _languageList.Add(new LanguageItem("SpanishPuertoRico", 20490));

        }

        public List<LanguageItem> GetLanguageList
        {
            get
            {
                return _languageList;
            }
            private set
            {
                _languageList = value;
            }
        }
    }

This is still to be refined.

Upvotes: 0

Views: 377

Answers (1)

Steve Padmore
Steve Padmore

Reputation: 1740

I think the issue is that you are iterating over data via COM everytime. If you store the languages in a list the first time you access them, you can then use the list each time - without accessing via COM.

Here is an example to demonstrate, store the list of languages once (if you are calling this multiple times). I used "Spanish (Latin American)" because it was the last in my list retrieved.

I've included stopwatches just to show the times of the different stages and lookups.

using Word = Microsoft.Office.Interop.Word;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;

namespace TestWordLanguages
{
    public class OfficeLanguages
    {
        private class LanguageItem
        {
            public Word.WdLanguageID Id { get; set; }
            public string Name { get; set; }

            public LanguageItem(Word.WdLanguageID id, string name)
            {
                Id = id;
                Name = name;
            }
        }

        List<LanguageItem> languageList = new List<LanguageItem>();

        public void MethodA()
        {
            Stopwatch sw1 = new Stopwatch();
            Stopwatch sw2 = new Stopwatch();
            Stopwatch sw3 = new Stopwatch();

            sw1.Start();
            Word.Application oWord = new Word.Application();
            Word.Document oWordDoc = new Word.Document();

            //Opening document here and doing stuff with it

            var Selection = oWordDoc.ActiveWindow.Selection;

            string strTgtLanguage = "Spanish (Latin America)";

            var test = oWord.Application.Languages;

            if (languageList.Count == 0)
            {
                foreach (Word.Language item in test)
                {
                    languageList.Add(new LanguageItem(item.ID, item.NameLocal));
                }
            }

            sw1.Stop(); // End of initial setup

            sw2.Start(); // Current lookup - using COM everytime
            foreach (Word.Language item in test)
            {
                if (item.NameLocal.IndexOf(strTgtLanguage) > -1)
                {
                    Selection.LanguageID = item.ID;
                    break;
                }
            }
            sw2.Stop();

            sw3.Start(); // Using stored list of languages
            Selection.LanguageID = languageList.Single(lang => lang.Name == strTgtLanguage).Id;
            sw3.Stop();

        }
    }
}

I thought you may want to repeatedly lookup the language, which is why I suggested placing the values in a list.

However, if you will be using the same server (and installation of MS Word) for the application, you can perform the initial lookup, get the values and embed them (or use a Resource File) to store them for use.

If however, this application will be placed on different client machines/servers, then the lookup will have to be made on each installation at least once - and then stored for future use in the application

When I tested this locally, it took around 500ms to generate the list or look through for the the last entry. If your application is looking up the values using COM over a network connection, that may be the reason for the extra slowness...

Upvotes: 1

Related Questions