4

In an application of mine, I need a large constant (actually static readonly) array of objects. The array is initialized in the type's static constructor.

The array contains more than a thousand items, and when the type is first used, my program experiences a serious slowdown. I would like to know if there is a way to initialise a large array quickly in C#.

public static class XSampa {
    public class XSampaPair : IComparable<XSampaPair> {
        public XSampaPair GetReverse() {
            return new XSampaPair(Key, Target);
        }
        public string Key { get; private set; }
        public string Target { get; private set; }
        internal XSampaPair(string key, string target) {
            Key = key;
            Target = target;
        }
        public int CompareTo(XSampaPair other) {
            if (other == null)
                throw new ArgumentNullException("other", 
                        "Cannot compare with Null.");
            if (Key == null)
                throw new NullReferenceException("Key is null!");
            if (other.Key == null)
                throw new NullReferenceException("Key is null!");
            if (Key.Length == other.Key.Length)
                return string.Compare(Key, other.Key, 
                        StringComparison.InvariantCulture);
            return other.Key.Length - other.Key;
        }
    }    
    private static readonly XSampaPair[] pairs, reversedPairs;
    public static string ParseXSampaToIpa(this string xsampa) {
        // Parsing code here...
    }
    public static string ParseIpaToXSampa(this string ipa) {
        // reverse code here...
    }
    static XSampa() {
        pairs = new [] {
            new XSampaPair("a", "\u0061"), 
            new XSampaPair("b", "\u0062"),
            new XSampaPair("b_<", "\u0253"), 
            new XSampaPair("c", "\u0063"),
            // And many more pairs initialized here...
        };
        var temp = pairs.Select(x => x.GetReversed());
        reversedPairs = temp.ToArray();
        Array.Sort(pairs);
        Array.Sort(reversedPairs);
    }
}

PS: I use to array to convert X-SAMPA phonetic transcription to a Unicode string with the corresponding IPA characters.

Minustar
  • 1,185
  • 1
  • 10
  • 23
  • 2
    Is it possible to use an `IEnumerable` so you can lazily yield return the array as needed? – jb. Apr 22 '12 at 23:16
  • 1
    @jb 's solution is good, but if you do not want to alter any code, you can simply initialize it during the startup of the application , maybe splash screen.. –  Apr 22 '12 at 23:17
  • Sorry edited after you had, please ignore it – Liam McInroy Apr 22 '12 at 23:29
  • Can't have a splash screen, everything must be able to run server side. – Minustar Apr 23 '12 at 00:34

2 Answers2

2

You can serialize a completely initialized onject into a binary file, add that file as a resource, and load it into your array on startup. If your constructors are CPU-intensive, you might get an improvement. Since your code appears to perform some sort of parsing, the chances of getting a decent improvement there are fairly high.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Is it possible to map the binary resource directly to some memory and make `pairs` point to that memory... à la C++? – Minustar Apr 22 '12 at 23:30
  • 1
    You can pull off something like that only with [*blittable value types*](http://msdn.microsoft.com/en-us/library/75dwhxf7.aspx), and only in unmanaged code. You would not map the resource to memory - you'd simply load it from a resource stream, but it's usually very fast. The consequence of this, however, is that you end up with value types in memory, which would require special care to avoid copying. – Sergey Kalinichenko Apr 22 '12 at 23:41
  • Would this be architecture independent (x64 vs. x86) and framework version independent (.net 3 vs .net 2)? Serialization is not my forte. – Minustar Apr 23 '12 at 00:31
  • @Minustar Since you ship your deserialization code along with the serialized data, you wouldn't be prone to mismatches in framework version. As far as the hardware architecture goes, .NET is architected to take care of it for you. – Sergey Kalinichenko Apr 23 '12 at 00:36
0

You could use an IEnumerable<yourobj> which would let you lazily yield return the enumerable only as needed.

The problem with this is you won't be able to index into it like you could using the array.

jb.
  • 9,921
  • 12
  • 54
  • 90