C#:指向多个整数的引用/指针数组

我想在数组中引用一些短路。 我以为我可以创建短裤,然后将它们添加到arrays中。 所以…每次更改引用的对象时,都会反映在数组中,反之亦然。 做一些试验使我确信它不是那么有效。 事实上,看起来价值是转移而不是参考。

下面的代码创建了两个short,将这些作为对象添加到数组中,然后更改原始short。 但是,当访问数组中假定的引用short时它没有改变,这使我相信它是一个与原始对象无关的全新对象。

Console.WriteLine("Testing simple references:"); short v1 = 1; short v2 = 2; object[] vs = new object[2]; vs[0] = v1; vs[1] = v2; v1 = 1024; v2 = 512; Console.WriteLine(" v1: " + (short)vs[0]); Console.WriteLine(" v2: " + (short)vs[1]); 

我在这里误解了一些基本的东西,如果有人可以解释,我会很感激,并且可能会指出一个可以做我想做的解决方案。

C#类型系统中有两种类型“值类型”和“引用类型”。

值类型按值复制; 当你复制一个时,你得到一个与原版无关的全新对象。

引用类型通过引用复制; 当您复制一个时,实际上是在复制对某个存储位置的引用。 您将获得两个引用,它们都引用一个对象。

短裤是价值类型。

如果你想让short成为引用类型,那么你可以创建一个引用类型包装器:

 class ReferenceType where T : struct { public T Value { get; set } public ReferenceType(T value) { this.Value = value; } } var v1 = new ReferenceType(1); var v2 = new ReferenceType(2); var vs = new ReferenceType[2] { v1, v2 }; v1.Value = 1024; v2.Value = 512; Console.WriteLine(vs[0].Value); Console.WriteLine(vs[1].Value); 

你去吧

现在,这将为您提供对short的引用访问,因为short实际存储在与该类的value属性关联的字段中。 如果你那么说:

 v2 = new ReferenceType(3); Console.WriteLine(vs[1].Value); 

你不会得到“3” – v2现在指的是与vs [1]不同的对象。 如果你真正想要捕获的是对变量的引用,那么你想要使用的是一个闭包

 class ReferenceToVariable { private Func getter; private Action setter; public ReferenceToVariable(Func getter, Action setter) { this.getter = getter; this.setter = setter; } public T Value { get { return getter(); } set { setter(value); } } } ... short v1 = 1; short v2 = 2; var vs = new [] { new ReferenceToVariable(()=>v1, x=>{v1=x;}), new ReferenceToVariable(()=>v2, x=>{v2=x;}) }; v1 = 123; vs[1].Value = 456; Console.WriteLine(vs[0].Value); // 123 Console.WriteLine(v2); // 456 

这里我们捕获数组对象,这些对象知道如何获取和设置v1和v2的当前值。

现在,如果您想要做的是直接为另一个变量创建一个别名 ,而没有这个对象,那么在C#中只有一种方法可以做到这一点:

 void M(ref short x) { x = 123; } ... short y = 1; M(ref y); 

现在“x”和“y”是同一变量的两个名称。 但是,当别名变量是方法的forms参数时,“为另一个变量创建别名”的概念仅适用于C#。 一般来说没有办法做到这一点。

现在,我们理论上可以做你想要的事情。 我们可以支持“ref locals”:

 short v1 = 1; ref short rv1 = ref v1; rv1 = 123; Console.WriteLine(v1); // 123 

也就是说,rv1成为v1的别名。 C#不支持这一点,但CLR确实如此,因此我们可以支持它。 但是,CLR不支持生成“ref”元素类型的数组或存储refs的字段。 所以从这个意义上讲,你无法做你想做的事。

C#支持一些特殊的“隐藏”function,用于传递对象类似于对变量的引用,但权重比上面提到的“两个委托”引用更轻。 但是,这些特殊function仅适用于奇怪的互操作场景,我建议不要使用它们。 (再一次,你不能创建一个存储类型引用的数组。)我不认为我会在这个答案中更多地谈论这些function; 你真的不想去那里,相信我。

Short是一种值类型 ,但您尝试使其行为类似于引用类型 。

您可以使用short属性创建一个类,然后使用该类的数组:

 public class MyShort { public short Value {get; set;} } public class SomeOtherClass { public void SomeMethod() { MyShort[] array = new MyShort[2]; array[0] = new MyShort {Value = 5}; array[1] = new MyShort {Value = 2}; array[0].Value = 3; } } 

你可以做一些工作来使它更顺畅(比如从一个转换器实现转换器到你的包装器类和返回)。

short类型是一种值类型 ,并且不像引用类型那样工作,其行为类似于您期望短路行为。 将值类型分配给变量时,将分配其值,而不是其引用。 vs[0]将保存您分配给v1的值的副本。

如果在更改原始值时确实需要更改数组中的值,则需要将short包装在引用类型中。 这是一个例子:

 public class ShortHolder { public short Value { get; set; } } 

然后你可以像这样使用它:

 var v1 = new ShortHolder() { Value=123; } var shortArray = new ShortHolder[1]; shortArray[0] = v1; 

如果更改v1.Value ,则shortArray[0].Value也将更改。

值类型称为值类型,因为它们在传递给方法时通过值传递或通过=运算符分配。

另一种(也是更正确的)方式是短裤,整数等不可变=>它们不能改变。 所以你基本上不能改变空头。 如果你需要一个short类型的对象来改变你需要创建一个类来保存这个对象,如下所示:

 public class ShortWrapper { public short ShortValue {get; set;} } class Program { static void Main(string[] args) { ShortWrapper short1 = new ShortWrapper{ ShortValue = 1}; ShortWrapper short2 = new ShortWrapper { ShortValue = 2 }; ShortWrapper[] shorts = new ShortWrapper[] { short1, short2 }; shorts[0].ShortValue = 5; Console.WriteLine(short1.ShortValue); } } 

本质上,代码正在用新对象替换short类型的对象。

如果你需要包裹裸露的短裤,你的设计可能会出现问题。 您要么已经使用了一些更复杂的对象,要么应该以其他方式使用short数组。 但我想你只是在测试。

根本问题是short是结构而不是对象。 所以基本上short的数组实际上是short的数组,而不是对短对象的引用数组。

要解决这个问题,你可以在一个class级“装箱”短片(但这会很乏味)

尝试使用以下内容:

 public class MyShort { public Value { get; set; } } 

如果向类添加转换运算符,则可以透明地使用ReferenceType ,就像float,int等实际是引用类型一样:

 class ReferenceType where T : struct { public T Value { get; set; } public ReferenceType(T value) { this.Value = value; } public static implicit operator ReferenceType(T b) { ReferenceType r = new ReferenceType(b); return r; } public static implicit operator T(ReferenceType b) { return b.Value; } } ReferenceType f1 = new ReferenceType(100f); f1 = 200f; float f2 = f1; 

通过使用explicit限定符而不是implicit explicit限定符,您可以要求对这些转换进行强制转换,如果您希望以更加冗长的方式使事情更清晰。