Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 获取值类型C的引用#_C#_Unsafe_Value Type - Fatal编程技术网

C# 获取值类型C的引用#

C# 获取值类型C的引用#,c#,unsafe,value-type,C#,Unsafe,Value Type,可能重复: 我想将我的值类型的引用复制到另一个值类型。是否可以不使用不安全的范例 int a = 10; int b = 15; a = b; // BUT I WANT TO SET REFERENCE OF b ! 这是我的真实例子。我创建枚举值类型并通过引用将其作为参数发送: public enum Test { test1, test2, test3 } public class MyTestClass1 { private Test _tes

可能重复:

我想将我的值类型的引用复制到另一个值类型。是否可以不使用
不安全的
范例

int a = 10;
int b = 15;
a = b; // BUT I WANT TO SET REFERENCE OF b !
这是我的真实例子。我创建枚举值类型并通过引用将其作为参数发送:

   public enum Test
{
    test1,
    test2,
    test3
}

public class MyTestClass1
{
    private Test _test;

    public MyTestClass1(ref Test test)
    {
        _test = test;
    }
}

public class Content
{
    public void Method()
    {
        Test e = Test.test1;
        /*some code*/
        var omyTestClass1 = new MyTestClass1(ref e);
        /*some code*/
        e = Test.test2;
        /*some code*/
        e = Test.test3;
    }
}

如果不使用
unsafe
或将值类型包装到结构/类中,则无法执行此操作

发件人:

将一个值类型变量赋值给另一个值类型变量会复制包含的值


如果不使用
unsafe
或将值类型包装到结构/类中,则无法执行此操作

发件人:

将一个值类型变量赋值给另一个值类型变量会复制包含的值


在同一方法中,不可能有一个局部变量包含对另一个局部变量的引用。类似的情况可能是,方法参数在调用方法中引用局部变量:

void CallingMethod()
{
    int a = 10;
    SomeMethod(ref a);
    ...
}

void SomeMethod(ref int b)
{
    // here, the variable b holds a reference to CallingMethod's local variable "a".
请注意,
b
可以包含对局部变量以外的对象的引用。例如,您可以像这样调用SomeMethod,在这种情况下,引用将指向堆上对象的字段:

class MyClass
{
    private int _a;
    public void AnotherCaller()
    {
        SomeMethod(ref _a);
        ...
    }
}

更新:Eric Lippert偶尔会写一些关于您询问的功能的文章,因为CLR确实支持它,而C#可以支持它。请参阅此答案,例如:

在同一方法中,不可能有一个局部变量包含对另一个局部变量的引用。类似的情况可能是,方法参数在调用方法中引用局部变量:

void CallingMethod()
{
    int a = 10;
    SomeMethod(ref a);
    ...
}

void SomeMethod(ref int b)
{
    // here, the variable b holds a reference to CallingMethod's local variable "a".
请注意,
b
可以包含对局部变量以外的对象的引用。例如,您可以像这样调用SomeMethod,在这种情况下,引用将指向堆上对象的字段:

class MyClass
{
    private int _a;
    public void AnotherCaller()
    {
        SomeMethod(ref _a);
        ...
    }
}

更新:Eric Lippert偶尔会写一些关于您询问的功能的文章,因为CLR确实支持它,而C#可以支持它。例如,看看这个答案:

我不确定我是否完全理解你,但是你可以将你的
int
包装在某个引用类型中,比如长度为
1
int[]
,或者一个元组,
tuple

因此:

由于
元组
不可变的,因此这是毫无意义的

但随后:

var a = new[] { 10 };
var b = new[] { 15 };
a = b;
// a and b reference the same object, and that'a a mutable object!
b[0] = 17;
// now a and b are still the same object, so also a[0] == 17

注意:这与您使用的
ref
关键字无关。您似乎无缘无故地使用了
ref

我不确定是否完全理解您的意思,但您可以将
int
封装在某个引用类型中,例如长度为
1
int[]
,或长度为1元组的
tuple

因此:

由于
元组
不可变的,因此这是毫无意义的

但随后:

var a = new[] { 10 };
var b = new[] { 15 };
a = b;
// a and b reference the same object, and that'a a mutable object!
b[0] = 17;
// now a and b are still the same object, so also a[0] == 17

注意:这与您使用的
ref
关键字无关。您似乎无缘无故地使用了
ref

如果您的方法实际上是:

public MyTestClass1 Method()
{
    Test e = Test.test1;
    /*some code*/
    var omyTestClass1 = new MyTestClass1(ref e);
    /*some code*/
    e = Test.test2;
    /*some code*/
    e = Test.test3;
    return omyTestClass1;
}
返回的值包含对堆栈上已存在但现在不存在的值类型的引用。现在,如果你尝试访问该字段,你可以得到任何东西

更糟糕的是,如果你写信给那个参考人怎么办?如果该引用存储在实际的调用堆栈中,而不是将其所有时间都花费在寄存器中(我们可以安全地假设,在引用它的类中有一个字段这一事实意味着它必须存在),那么现在有什么呢?它可以是对对象的引用。可能是回信地址。写入它可能会在核心bug上引起一些奇怪的fandango,很可能是在写入之后的一段时间,因此很难调试

我们会失去一些基本的保障。在您写入该值之后,几乎任何地方的任何代码都可能以某种奇怪的方式失败

在这一点上,值得注意的是,C++和.NET本身(也就是说,你可以在.NET中所做的一切,包括在C++中不能使用的)都允许本地参考文件和REF返回值不允许REF字段。 最接近的方法是捕获lambdas和匿名方法。在这里,局部变量不存储在堆栈中,而是存储在堆中,以允许它们与生命捕获的lambda一样生存(并在收集最后一个lambda时被收集)。您当然可以使用它来维护对对象中以局部形式开始的对象的引用

或者,您可以使用完成必要工作的类包装值类型。举个例子,当我有类似的需求时,我使用了一个:

public sealed class SharedInt
{
  private int _value;
  /// <summary>Creates a new SharedInt with a value of zero.</summary>
  public SharedInt(){}
  /// <summary>Creates a new SharedInt.</summary>
  /// <param name="value">The initial value of the object.</param>
  public SharedInt(int value)
  {
    _value = value;
  }
  /// <summary>Returns the value of the SharedInt.</summary>
  public int Value
  {
    get { return _value; }
  }
  /// <summary>Returns the value of the SharedInt.</summary>
  /// <param name="ri">The SharedInt to cast.</param>
  /// <returns>An integer of the same value as the SharedInt.</returns>
  public static implicit operator int(SharedInt ri)
  {
    return ri._value;
  }
  /// <summary>Atomically increment the value of the SharedInt by one.</summary>
  /// <returns>The new value.</returns>
  public int Increment()
  {
    return Interlocked.Increment(ref _value);
  }
  /// <summary>Atomically decrement the value of the SharedInt by one.</summary>
  /// <returns>The new value.</returns>
  public int Decrement()
  {
    return Interlocked.Decrement(ref _value);
  }
  /// <summary>Atomically add a value to the SharedInt.</summary>
  /// <param name="addend">The number to add to the SharedInt.</param>
  /// <returns>The new value.</returns>
  public int Add(int addend)
  {
    return Interlocked.Add(ref _value, addend);
  }
  /// <summary>Atomically replace the value of the SharedInt, returning the previous value.</summary>
  /// <param name="value">The number to set the SharedInt to.</param>
  /// <returns>The old value.</returns>
  public int Exchange(int value)
  {
    return Interlocked.Exchange(ref _value, value);
  }
  /// <summary>Atomically subtract a value from the SharedInt.</summary>
  /// <param name="subtrahend">The number to subtract from the SharedInt.</param>
  /// <returns>The new value.</returns>
  public int Subtract(int subtrahend)
  {
    return Interlocked.Add(ref _value, -subtrahend);
  }
}

公开公开一个字段有很大的缺点(这就是为什么我们通常从不这样做),但大多数缺点不适用于这种情况(我们希望能够从外部完全操纵它)这意味着您甚至可以将
值作为
ref
out
参数传递。

如果您的方法实际上是:

public MyTestClass1 Method()
{
    Test e = Test.test1;
    /*some code*/
    var omyTestClass1 = new MyTestClass1(ref e);
    /*some code*/
    e = Test.test2;
    /*some code*/
    e = Test.test3;
    return omyTestClass1;
}
返回的值包含对堆栈上已存在但现在不存在的值类型的引用。现在,如果你尝试访问该字段,你可以得到任何东西

更糟糕的是,如果你写信给那个参考人怎么办?如果该引用存储在实际的调用堆栈中,而不是将其所有时间都花费在寄存器中(我们可以安全地假设,在引用它的类中有一个字段这一事实意味着它必须存在),那么现在有什么呢?它可以是对对象的引用。可能是回信地址。写入它可能会在核心bug上引起一些奇怪的fandango,很可能是在写入之后的一段时间,因此很难调试

我们会失去一些基本的保障。在您写入该值之后,几乎任何地方的任何代码都可能以某种奇怪的方式失败

在这一点上,值得注意的是,C++和.NET本身(也就是说,你可以在.NET中所做的一切,包括在C语言中不能使用的),它们既允许本地引用又允许RUTU。