【发布时间】:2019-03-25 13:33:04
【问题描述】:
我提前道歉。我的域主要是 C(和 C++)。我正在尝试在 C# 中编写类似的东西。让我用代码解释一下。
在 C++ 中,我可以使用在编译时处理并存储在 PE 文件的只读部分中的大型静态数组。例如:
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;
}
在上面的例子中,static const MY_ASSOC all_assoc 的初始化不会在运行时被调用。它在编译时完全处理。
现在如果我用 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;
}
private static readonly NameValue[] g_arrNV_Assoc 行必须在宿主类初始化期间调用一次,并且针对该数组中的每个元素执行此操作!
所以我的问题是——我能否以某种方式对其进行优化,以便将存储在 g_arrNV_Assoc 数组中的数据存储在 PE 部分中而不是在运行时初始化?
附言。我希望我的术语能让 .NET 人员清楚。
【问题讨论】:
-
我对 c 和 c++ 一无所知,但在 c# 中,
readonly和const意味着不同的东西。const在编译时被替换为它在整个代码中的值。readonly仅仅意味着任何变量只能在创建类型的实例时分配 -static readonly意味着变量只能在类型初始化过程中分配,这是一个您无法控制的 clr 后台进程在你的代码中。 -
g_arrNV_Assoc看起来是一个相当低效的数据结构,因为你是foreach'ingname == nv.name这应该是一个字典,是的,它会在第一次使用时加载一次。并且对GetValueForName的每个后续调用都只会查找一个哈希表。我的意思是你还能做什么,除了在加载时加载一个非托管内存,并通过它迭代指针以获得你想要的结果。你到底想在这里实现什么,更好的加载时间? -
@TheGeneral:好吧,当然我并没有声称我的查找算法的效率。我只是在询问数组初始化部分。我选择它只是因为缺少打字。所以是的,使用字典(即使在 C++ 中)也需要时间来加载它。
-
为了在 C 中更有效地查找,我会按名称按字母顺序对静态数组进行排序(在源代码中,可能通过 PY 脚本),并在我的函数中使用二进制搜索算法.但正如你可以想象的那样,它需要的代码比我上面显示的要多得多,因此我选择了一个更简单的例子。但同样,那部分与我的问题无关。这与有效加载大型静态(即不变/不可变)数组有关。 (无论您在 .net 中如何称呼它:列表、字典、地图等)
标签: c# arrays .net performance arraylist