2

Using C#, I have a static class that has a static list of a custom type. Here is the custom type:

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

And here is the static class that uses this type:

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

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

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

What I am trying to do is to use this list from another class, to return the the items from the list. I want to specify the Name and I want to get the Id back.

I tried to use this:

using Word = Microsoft.Office.Interop.Word;

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

oWord.Selection.LanguageID = LanguageList.Single(lang => lang.Name == strTgtLanguage).Id;

But I get a compile error that reads:

'LanguageList' does not contain a definition for 'Single'

I tried to look at other similar post, such as How to access all specific versions of a generic static class in C#? and How to access member of a static class which is inside another static class and others, but I can't figure it out based on these.

Also the reason I am using a hard coded enumeration because if I use the COM object Office.Interop.Word, then it takes forever (over 2 minutes) to add all the 250+ items to the list.

Can somebody help me a point out what I am doing wrong and why can't I access the list, or if there is a better approach? Thanks in advance.

Community
  • 1
  • 1
ib11
  • 2,530
  • 3
  • 22
  • 55
  • 1
    I'm genuinely curious how this code can compile when your static class is inheriting something other than `object`. There has to be something going over my head. – Drew Kennedy May 08 '16 at 00:10
  • Good point, my bad, I forgot to update that as well. I fixed all the compiler errors, most of which showed up only at build time. I just forgot to update it here. – ib11 May 08 '16 at 00:26
  • All good. I saw it and was so confused lol. – Drew Kennedy May 08 '16 at 00:28

3 Answers3

4

I think your approach is not appropriate.

If you're hard-coding the list, then why would you have a setter? Also, the list should then be immutable, correct?

I believe this would work better for your need:

    public static class LanguageList
{
    private static readonly List<LanguageItem> _languageList = new List<LanguageItem>(new[]
    {
        new LanguageItem("Arabic", 1025),
        new LanguageItem("Bulgarian", 1026),
        new LanguageItem("Catalan", 1027),
        new LanguageItem("TraditionalChinese", 1028),
        new LanguageItem("Czech", 1029),
        new LanguageItem("Danish", 1030),
        new LanguageItem("German", 1031),
        new LanguageItem("Greek", 1032),
        new LanguageItem("EnglishUS", 1033),
        new LanguageItem("Spanish", 1034),
        new LanguageItem("Finnish", 1035),
        new LanguageItem("French", 1036),
        new LanguageItem("Hebrew", 1037),
        new LanguageItem("Hungarian", 1038),
        new LanguageItem("Icelandic", 1039),
        new LanguageItem("Italian", 1040),
        new LanguageItem("Japanese", 1041),
        new LanguageItem("Korean", 1042),
        new LanguageItem("Dutch", 1043),
    });

      public static IEnumerable<LanguageItem> GetLanguages ()
    {
        return _languageList;
    }

    public static LanguageItem GetLanguageItem(string languageName)
    {
        return _languageList.SingleOrDefault(li => li.Name.Equals(languageName));
    }
}
Wesley Long
  • 1,708
  • 10
  • 20
  • Correct, I don't want to change the list at all from the code. So how would I access the list then from a method of another class? Just `GetLanguages.Name`? – ib11 May 07 '16 at 23:58
  • IEnumerable is queryable with LINQ. Would a dictionary be better? – Wesley Long May 07 '16 at 23:59
  • No, no list is simple and totally fine, but I wondered on the eact LINQ expression, if it needs to be a LINQ even. – ib11 May 08 '16 at 00:01
  • I just added a method to show you the LINQ. I don't know how you intend to use it. You can just as easily use a dictionary, and it would be quicker. Your call. This is worth a read: https://msdn.microsoft.com/en-us/library/gg712875(v=vs.110).aspx – Wesley Long May 08 '16 at 00:03
  • Thanks. The line `public static IEnumerable GetLanguages => _languageList;` gives me a compiler error, that says, "LanguageList._languageList' is a 'field' but is used like a 'type'" Am I missing something? – ib11 May 08 '16 at 00:16
  • @ibi11 - Are you using an older version of C#? That's a new feature. Let me make that backwards compatible, here. – Wesley Long May 08 '16 at 00:25
  • Thank you. I wondered. It is Visual C# 2013. Also on the last line you mean `li.Name.Equals(languageName)` in the LINQ, right? – ib11 May 08 '16 at 00:28
  • 2
    Ah, good catch. I didn't copy your original class. I had made my own because I didn't want to mess around with the MSWord reference. I should be more careful. :) Also - I'm using VS2015, so that inline expression probably didn't do so well on VS2013. – Wesley Long May 08 '16 at 00:30
  • You can now vote up the question :-) Just kidding. But you can if you care for it. I would never figured this out alone (I mean not never, but would take forever.) I just started learning C# less than a month ago, straight upgrade from VBA. So a lot of things are entirely new. If it weren't for SO and the awesome guys like you and the others, I would be nowhere. Now I have a fully functioning plugin I though I would take months to build. So thank you. – ib11 May 08 '16 at 00:36
  • OK. It works like a charm, it does return the ID, but somehow my cast does not work, after I set it like this: `Selection.LanguageID = (Word.WdLanguageID)MatchedLanguage.Id;` The `Selection.LanguageID` value is `999999` instead of 1038... Any idea? – ib11 May 08 '16 at 00:42
  • Selection? I think you just stepped outside the scope of the original question. Is this a ListBox somewhere? In a Winform? Something like that? – Wesley Long May 08 '16 at 00:45
  • Probably it was a trick question to begin with! ;-) See the third code snippet in the OP. – ib11 May 08 '16 at 00:46
  • 2
    Yeah, you're off into the COM Word Interop stuff, now. I think you have a new question to write up. – Wesley Long May 08 '16 at 00:46
  • LOL. OK. I changed however the `ListItem.Id` to an `int` and cast it in the module code... Let's see before I pop the question... – ib11 May 08 '16 at 00:49
  • OK, we have it. Thanks a lot. The reason it returns `9999999` because the selection is a table. The actual text does change. – ib11 May 08 '16 at 01:00
  • 2
    If you don't need the language list to maintain order, consider replacing the `List` with a `HashSet`. – yaakov May 08 '16 at 02:48
  • @codran Thanks for the tip, good point. What is the pros and contras? Can you elaborate or give a link to some good comparison reference? – ib11 May 08 '16 at 02:56
  • 2
    @ib11 Mostly lookup performance. See http://stackoverflow.com/questions/25615764/list-add-vs-hashset-add-for-small-collections-in-c-sharp – yaakov May 08 '16 at 03:27
1

.Single(...) from System.Linq is an extension method, but you're trying to use it as a static method on LanguageList.

If you want to use the LINQ methods, you need to operate on the actual list object, not the class - LanguageList.LanguageListItems.

i.e. LanguageList.LanguageListItems.Single(...).

Furthermore, since it's a static class, the inheritance from List<T> is irrelevant and can probably be dropped.

yaakov
  • 5,552
  • 35
  • 48
1

1) You can't use .Single() because LanguageList is a class, not an instance of a class which implements IEnumerable< T >. It should work if you do:

new LanguageList().GetLanguageList.Single();

But don't actually do that. There's no reason for GetLanguageList to be an instance member; it should be static.

2) You should not expose the language list, assuming it is intended to be immutable.

3) You should probably use a Dictionary< string, Word.WdLanguageID > for your language table. It will be a bit more efficient, and uniqueness is enforced during construction, not during each lookup.

4) Add a static language accessor to LanguageList (assuming a Dictionary<>):

public static bool TryGetLanguageId(string name, out Word.WdLanguageID id)
{
    return _languageList.TryGetValue(name, out id);
}
glenebob
  • 1,943
  • 11
  • 11