Generic中的ref类型和值类型

时间:2021-09-25 16:12:55

I was working on a demo method and found something strange(at least to me :-))

我正在研究一种演示方法并发现一些奇怪的东西(至少对我而言:-))

enter code here  class Program
{
    public void AnotherSwap<T>(T a, T b)  
    {
        T temp;
        temp = a;
        a = b;
        b = temp;

        Console.WriteLine(a);
        Console.WriteLine(b);

    }


    public void swap<T>(T a, T b) where T : MyInt  // Passing without ref
    {
        object temp;
        temp = a.MyProperty;
        a.MyProperty = b.MyProperty;
        b.MyProperty = (int)temp;

        Console.WriteLine(a.MyProperty);
        Console.WriteLine(b.MyProperty);



    }

    static void Main(string[] args)
    {
        Program p = new Program();
        MyInt a = new MyInt() { MyProperty = 10 };
        MyInt b = new MyInt() { MyProperty = 20 };
        p.swap<MyInt>(a, b);
        Console.WriteLine(a.MyProperty); // changed values get reflected
        Console.WriteLine(b.MyProperty); // changed values get reflected

        Console.WriteLine("Another Swap");
        object x = 10;
        object y = 20;
        p.AnotherSwap(x, y);

        Console.WriteLine(x);  // changed values are not getting  reflected
        Console.WriteLine(y);  // changed values are not getting  reflected

         Console.ReadKey();


    }
   public class MyInt
    {
        public int MyProperty { get; set; }

    }




}

Here when I am calling the swap() , though I haven't mentioned ref , the changed values are automatically getting reflected (as in p.swap(a, b); a and b are instance of Myint and thus will by default work as ref..as per my understanding.) But same should happen with Anotherswap() here also I am passing object x,y but now the values are not getting reflected in Main() .i.e. now its working as a value type. Can somebody explain where my understanding is going wrong. Let me know if u guys want more info.

这里当我调用swap()时,虽然我没有提到ref,但是更改的值会自动反映出来(如p.swap(a,b); a和b是Myint的实例,因此默认情况下会工作作为参考...根据我的理解。)但同样的情况应该发生在Anotherswap()这里我也传递对象x,y,但现在值没有反映在Main().ie现在它作为一种价值类型。有人可以解释我的理解是错误的。如果你们想要更多信息,请告诉我。

3 个解决方案

#1


When MyInt type is cast as Object, it gets cast as a val type. Object cannot be treated like a reference since its representing both val and ref, it must be explicitly passed by ref.

当MyInt类型被转换为Object时,它将被转换为val类型。对象不能像引用一样对待,因为它表示val和ref,它必须由ref显式传递。

int can be cast as an object, and its still treated as a val. string can be cast as object, and its treated as a val. Even though normally it would be a ref type.

int可以作为对象进行转换,并且仍然将其视为val。 string可以作为对象进行转换,并将其视为val。即使通常它会是一个ref类型。

If you did the AnotherSwap and passed T in as MyInt, you would get the same results as before. If you called the original swap algorithm with objects, you would get the same output as the latter.

如果您使用AnotherSwap并将T in作为MyInt传递,您将获得与之前相同的结果。如果使用对象调用原始交换算法,则会得到与后者相同的输出。

#2


Your question is misleading, and the answer is actually simpler than that:

你的问题是误导性的,答案实际上比这更简单:

In your Swap function, you are swapping the values of the MyProperty properties in those classes, not the actual classes themselves. This would be easily proved if you had another property in the MyInt class called "Name" or something. After the call to Swap, you would see that the Name property remained unchanged.

在Swap函数中,您将交换这些类中的MyProperty属性的值,而不是实际的类本身。如果你在MyInt类中有另一个名为“Name”的属性,那么很容易证明这一点。在调用Swap之后,您会看到Name属性保持不变。

The reason that in AnotherSwap nothing interesting is happening is because you aren't passing the types by ref at all, so the assignments that you perform to the object's pointer inside the function don't modify the original objects' pointers from the caller's perspective.

在AnotherSwap中没有发生任何有趣事情的原因是因为你根本没有通过ref传递类型,所以你对函数内部对象指针执行的赋值不会从调用者的角度修改原始对象的指针。

Something else to consider is that when you're turning 10 into an object, you're actually boxing the object, and that's something else you need to keep in mind. When writing generics that you want to behave differently for reference versus value types, I always just use "where T : class" for reference types and "where T : struct" for value types. The names of the two functions cannot be the same though.

还有一点需要考虑的是,当你将10变成一个物体时,你实际上正在装箱,这是你需要记住的其他东西。在编写泛型时,您希望对于引用与值类型的行为不同,我总是只使用“where T:class”作为引用类型,使用“where T:struct”作为值类型。但是这两个函数的名称不能相同。

#3


the second set of the objects [object x = 1] is converted to int which is a value type since it is assigned an int at initialization, so it is treated as an int which is a value type.

第二组对象[object x = 1]被转换为int,这是一个值类型,因为它在初始化时被赋予了一个int,因此它被视为一个值,它是一个值类型。

if you run the following snippet you'll see my point.

如果你运行以下代码片段,你会看到我的观点。

object test = 1;
Console.Writeline(test.GetType());

returns: "typeof (Int32)"

so the type of your object is no longer object but Int32 which is a value type.

所以对象的类型不再是对象,而是Int32,它是一种值类型。

object test = 1;
Console.Writeline(test.GetType().IsByRef);

returns: "false"

#1


When MyInt type is cast as Object, it gets cast as a val type. Object cannot be treated like a reference since its representing both val and ref, it must be explicitly passed by ref.

当MyInt类型被转换为Object时,它将被转换为val类型。对象不能像引用一样对待,因为它表示val和ref,它必须由ref显式传递。

int can be cast as an object, and its still treated as a val. string can be cast as object, and its treated as a val. Even though normally it would be a ref type.

int可以作为对象进行转换,并且仍然将其视为val。 string可以作为对象进行转换,并将其视为val。即使通常它会是一个ref类型。

If you did the AnotherSwap and passed T in as MyInt, you would get the same results as before. If you called the original swap algorithm with objects, you would get the same output as the latter.

如果您使用AnotherSwap并将T in作为MyInt传递,您将获得与之前相同的结果。如果使用对象调用原始交换算法,则会得到与后者相同的输出。

#2


Your question is misleading, and the answer is actually simpler than that:

你的问题是误导性的,答案实际上比这更简单:

In your Swap function, you are swapping the values of the MyProperty properties in those classes, not the actual classes themselves. This would be easily proved if you had another property in the MyInt class called "Name" or something. After the call to Swap, you would see that the Name property remained unchanged.

在Swap函数中,您将交换这些类中的MyProperty属性的值,而不是实际的类本身。如果你在MyInt类中有另一个名为“Name”的属性,那么很容易证明这一点。在调用Swap之后,您会看到Name属性保持不变。

The reason that in AnotherSwap nothing interesting is happening is because you aren't passing the types by ref at all, so the assignments that you perform to the object's pointer inside the function don't modify the original objects' pointers from the caller's perspective.

在AnotherSwap中没有发生任何有趣事情的原因是因为你根本没有通过ref传递类型,所以你对函数内部对象指针执行的赋值不会从调用者的角度修改原始对象的指针。

Something else to consider is that when you're turning 10 into an object, you're actually boxing the object, and that's something else you need to keep in mind. When writing generics that you want to behave differently for reference versus value types, I always just use "where T : class" for reference types and "where T : struct" for value types. The names of the two functions cannot be the same though.

还有一点需要考虑的是,当你将10变成一个物体时,你实际上正在装箱,这是你需要记住的其他东西。在编写泛型时,您希望对于引用与值类型的行为不同,我总是只使用“where T:class”作为引用类型,使用“where T:struct”作为值类型。但是这两个函数的名称不能相同。

#3


the second set of the objects [object x = 1] is converted to int which is a value type since it is assigned an int at initialization, so it is treated as an int which is a value type.

第二组对象[object x = 1]被转换为int,这是一个值类型,因为它在初始化时被赋予了一个int,因此它被视为一个值,它是一个值类型。

if you run the following snippet you'll see my point.

如果你运行以下代码片段,你会看到我的观点。

object test = 1;
Console.Writeline(test.GetType());

returns: "typeof (Int32)"

so the type of your object is no longer object but Int32 which is a value type.

所以对象的类型不再是对象,而是Int32,它是一种值类型。

object test = 1;
Console.Writeline(test.GetType().IsByRef);

returns: "false"