2

I apologize in advance. My domain is mostly C (and C++). I'm trying to write something similar in C#. Let me explain with code.

In C++, I can use large static arrays that are processed during compile-time and stored in a read-only section of the PE file. For instance:

typedef struct _MY_ASSOC{
    const char* name;
    unsigned int value;
}MY_ASSOC, *LPMY_ASSOC;

bool GetValueForName(const char* pName, unsigned int* pnOutValue = nullptr)
{
    bool bResult = false;
    unsigned int nValue = 0;

    static const MY_ASSOC all_assoc[] = {
        {"name1", 123},
        {"name2", 213},
        {"name3", 1433},
        //... more to follow
        {"nameN", 12837},
    };

    for(size_t i = 0; i < _countof(all_assoc); i++)
    {
        if(strcmp(all_assoc[i].name, pName) == 0)
        {
            nValue = all_assoc[i].value;
            bResult = true;
            break;
        }
    }

    if(pnOutValue)
        *pnOutValue = nValue;

    return bResult;
}

In the example above, the initialization of static const MY_ASSOC all_assoc is never called at run-time. It is entirely processed during the compile-time.

Now if I write something similar in C#:

    public struct NameValue
    {
        public string name;
        public uint value;
    }

    private static readonly NameValue[] g_arrNV_Assoc = new NameValue[] {
        new NameValue() { name = "name1", value = 123 },
        new NameValue() { name = "name2", value = 213 },
        new NameValue() { name = "name3", value = 1433 },
        // ... more to follow
        new NameValue() { name = "nameN", value = 12837 },
    };

    public static bool GetValueForName(string name, out uint nOutValue)
    {
        foreach (NameValue nv in g_arrNV_Assoc)
        {
            if (name == nv.name)
            {
                nOutValue = nv.value;
                return true;
            }
        }

        nOutValue = 0;
        return false;
    }

The line private static readonly NameValue[] g_arrNV_Assoc has to be called once during the host class initialization, and it is done for every single element in that array!

So my question -- can I somehow optimize it so that the data stored in g_arrNV_Assoc array is stored in the PE section and not initialized at run-time?

PS. I hope I'm clear for the .NET folks with my terminology.

4
  • I know nothing of c and c++, but in c#, readonly and const means different things. A const is replaced at compile time with it's value throughout the code. readonly simply means that whatever variable can only be assigned to when creating an instance of the type - static readonly means that the variable can only be assigned to during the type initialization process, which is a clr background process you have no control over in your code. Commented Oct 21, 2018 at 7:37
  • g_arrNV_Assoc looks like a fairly inefficient data structure since you are foreach'ing name == nv.name this should be a dictionary, yes it will load once on first use. and each subsequent call on GetValueForName will just look up a HashTable. i mean what else could you do, well apart from loading a glob of unmanaged memory on load, and iterating pointer wise through it for your desired result. What are you actually trying to achieve here, better load time? Commented Oct 21, 2018 at 7:40
  • @TheGeneral: Well, sure I'm not claiming efficiency of my lookup algorithm. I'm just asking about array initialization part. I chose it merely for lack of typing. So yeah, with the dictionary (even in C++) it will take time to load it up as well. Commented Oct 21, 2018 at 7:44
  • For a more efficient lookup in C, I would sort my static array by name in alphabetical order (in the source code, possibly via a PY script) and use the binary search algorithm on it in my function. But as you can imagine it will take way more code than I showed above, thus I chose an easier example. But again, that part has nothing to do with my question. Which is about efficiently of loading of a large static (i.e. unchanging/immutable) array. (Whatever you call it in .net: list, dictionary, map, etc.) Commented Oct 21, 2018 at 7:51

1 Answer 1

1

Indeed the terminology is sufficient enough, large static array is fine.

There is nothing you can really do to make it more efficient out of the box.

It will load initially once (at different times depending on which version of .net and if you have a static constructor). However, it will load before you call it.

Even if you created it empty with just the predetermined size, the CLR is still going to initialize each element to default, then you would have to buffer copy over your data somehow which in turn will have to be loaded from file.

The question are though

  • How much overhead does loading the default static array of struct actually have compared to what you are doing in C
  • Does it matter when in the lifecycle of the application when its loaded

And if this is way too much over-head (which i have already assumed you have determined), what other options are possibly available outside the box?

You could possibly pre-allocate a chunk of unmanaged memory, then read and copy the bytes in from somewhere, then inturn access using pointers.

You could also create this in a standard Dll, Pinvoke just like an other un-managed DLL. However i'm not really sure you will get much of a free-lunch here anyway, as there is overhead to marshal these sorts of calls to load your dll.

If your question is only academic, these are really your only options. However if this is actually a performance problem you have, you will need to try and benchmark this for micro-optimization and try to figure out what is suitable to you.

Anyway, i don't profess to know everything, maybe someone else has a better idea or more information. Good luck

Sign up to request clarification or add additional context in comments.

1 Comment

Well, yeah, it's more of an academic curiosity. I'm not loading GB of data in there. IDK, I just don't like wasting CPU cycles if I don't have to. Plus, I guess I'm (still) learning C#. So thanks for the explanation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.