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

C#:指向多个整数的引用/指针数组,c#,pointers,integer,reference,short,C#,Pointers,Integer,Reference,Short,我想在一个数组中保留对一些短裤的引用。我认为我可以创建短裤,然后将它们添加到阵列中。所以每次更改被引用对象时,这都会反映在数组中,反之亦然。做一些试验使我确信,它不是那样工作的。事实上,它看起来像是传递了值,但不是引用 下面的代码创建了两个短片,将它们作为对象添加到数组中,然后更改原始短片。然而,当访问数组中的假定引用短对象时,它没有改变,这使我相信它是一个与原始对象无关的全新对象 Console.WriteLine("Testing simple references:");

我想在一个数组中保留对一些短裤的引用。我认为我可以创建短裤,然后将它们添加到阵列中。所以每次更改被引用对象时,这都会反映在数组中,反之亦然。做一些试验使我确信,它不是那样工作的。事实上,它看起来像是传递了值,但不是引用

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

        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]);

我在这里误解了一些基本的东西,如果有人能解释一下,也许能给我指出一个解决方案,我会很感激的

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

要解决这个问题,你可以在一节课中“框”出短文(但这会很乏味)

尝试以下方法:

public class MyShort { public Value { get; set; } }
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
到包装类的转换,然后再返回)。

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

值类型按值复制;复制一个对象时,会得到一个与原始对象无关的全新对象

引用类型按引用复制;复制一个引用时,实际上是将引用复制到某个存储位置。得到两个引用,它们都引用一个对象

短裤是价值型的

如果希望short成为引用类型,则可以制作引用类型包装器:

class ReferenceType<T> where T : struct
{
    public T Value { get; set }
    public ReferenceType(T value) { this.Value = value; }
}

var v1 = new ReferenceType<short>(1);
var v2 = new ReferenceType<short>(2);
var vs = new ReferenceType<short>[2] { v1, v2 };
v1.Value = 1024;
v2.Value = 512;
Console.WriteLine(vs[0].Value);
Console.WriteLine(vs[1].Value);
现在“x”和“y”是同一变量的两个名称。然而,只有当别名变量是方法的形式参数时,“为另一个变量生成别名”的概念才适用于C#。一般来说,没有办法做到这一点

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


更新:我在这里讨论的“理论”特性被添加到C#7.0中


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


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

short类型是一种类型,它不像参考类型那样工作,而参考类型的行为就像你期望你的短裤那样。将值类型指定给变量时,将指定其值,而不是其引用
vs[0]
将保存您分配给
v1
的值的副本

如果在更改原始值时确实需要更改数组中的值,则需要在引用类型中换行。以下是一个例子:

public class ShortHolder {
  public short Value { get; set; }
}
然后你可以这样使用它:

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

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);
    }
}


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

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

另一种(也是更正确的)看法是,short、int等是不可变的=>它们不能更改。所以你基本上不能改变一个短线。如果需要在某处更改short类型的对象,则需要创建一个类来保存该对象,如下所示:

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

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类型的对象


顺便说一句,如果你需要包一个裸体短裤,你的设计可能有问题。您应该已经在使用一些更复杂的对象,或者应该以其他方式处理短裤数组。但我猜您只是在测试。

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

class ReferenceType<T> where T : struct
{
    public T Value { get; set; }
    public ReferenceType(T value) { this.Value = value; }
    public static implicit operator ReferenceType<T>(T b)
    {
        ReferenceType<T> r = new ReferenceType<T>(b);
        return r;
    }
    public static implicit operator T(ReferenceType<T> b)
    {
        return b.Value;
    }
}
ReferenceType<float> f1 = new ReferenceType(100f);
f1 = 200f;
float f2 = f1;
类引用类型,其中T:struct
{
公共T值{get;set;}
公共引用类型(T值){this.value=value;}
公共静态隐式运算符引用类型(TB)
{
ReferenceType r=新的ReferenceType(b);
返回r;
}
公共静态隐式运算符T(引用类型b)
{
返回b.值;
}
}
ReferenceType f1=新的ReferenceType(100f);
f1=200f;
浮动f2=f1;

通过使用
显式
限定符而不是
隐式
,您可以要求对这些转换进行强制转换,如果您想以牺牲一点冗长为代价使事情更清楚。

我将在该类中添加一个
where T:struct
。它不是严格必要的,但更符合类型的目标。由于Eric没有给出关于C#的“隐藏”特性的详细信息,我发布了一个关于这些特性的链接:我震惊地发现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);
    }
}

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