我想修改数组内部的结构字段,而不必设置整个结构。在下面的示例中,我想在数组中设置元素543的一个字段。我不想复制整个元素(因为复制MassiveStruct会损害性能)。
class P
{
struct S
{
public int a;
public MassiveStruct b;
}
void f(ref S s)
{
s.a = 3;
}
public static void Main()
{
S[] s = new S[1000];
f(ref s[543]); // Error: An object reference is required for the non-static field, method, or property
}
}
有没有办法在C#中做到这一点?或者我总是要从数组中复制整个结构,修改副本,然后将修改后的副本放回到数组中。
答案 0 :(得分:10)
唯一的问题是您尝试从静态方法调用实例方法,而不使用P
的实例。
让f
成为一个静态方法(或创建一个P
的实例来调用它),它会没问题。这都是关于阅读编译器错误:))
话虽如此,我强烈建议你:
答案 1 :(得分:2)
虽然Jon Skeet对于您的程序无法编译的原因是正确的,但您可以这样做:
s[543].a = 3;
...它将直接在数组中的结构上运行,而不是在副本上运行。
请注意,此提示仅适用于数组,其他集合(如列表)将从indexer-getter返回一个副本(如果您在结果值上尝试类似的操作,则会给出编译器错误) 。
另一方面,mutable structs are considered evil。您是否有充分的理由不想让S
成为一个班级?
答案 2 :(得分:0)
您可以尝试使用不包含实际数据的forwarding empty struc t,但只保留dataprovider对象的索引。这样,您可以存储大量数据,而不会使对象图复杂化。 我非常肯定,只要您不尝试将其编组为非托管代码,在您的情况下使用转发emtpy结构替换您的巨型结构应该非常容易。
看看这个结构。它可以包含尽可能多的数据。诀窍在于您将实际数据存储在另一个对象中。通过这种方式,您可以获得引用语义和结构的优势,这些结构比类对象消耗更少的内存,并且由于更简单的对象图(如果您有许多实例(数百万))而更快的GC循环。
[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct ForwardingEmptyValueStruct
{
int _Row;
byte _ProviderIdx;
public ForwardingEmptyValueStruct(byte providerIdx, int row)
{
_ProviderIdx = providerIdx;
_Row = row;
}
public double V1
{
get { return DataProvider._DataProviders[_ProviderIdx].Value1[_Row]; }
}
public int V2
{
get { return DataProvider._DataProviders[_ProviderIdx].Value2[_Row]; }
}
}