2009-07-07 6 views
0

я работал над демо-метода и нашли что-то странное (по крайней мере для меня :-))исх типа в Generic

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

    } 




} 

Вот когда я звоню своп(), хотя убежище I 't упомянутый ref, измененные значения автоматически отражаются (как в p.swap (a, b); a и b являются экземпляром Myint и, таким образом, будут работать по умолчанию как ref..as для моего понимания.) Но то же самое должно произойти с Anotherswap() здесь также я передаю объект x, y, но теперь значения не отражаются в Main() .ie теперь он работает как тип значения. Может кто-нибудь объяснить, где мое понимание идет не так. Дайте мне знать, если вы хотите получить больше информации.

ответ

1

Когда тип MyInt отличен как Object, он становится отличным как тип val. Объект нельзя рассматривать как ссылку, поскольку он представляет как val, так и ref, он должен быть явно передан ref.

int может быть отлит как объект, а его все еще обрабатывается как val. Строка может быть отлита как объект, а ее обрабатывается как val. Хотя обычно это будет тип ref.

Если вы сделали AnotherSwap и передали T в качестве MyInt, вы получите те же результаты, что и раньше. Если вы вызвали оригинальный алгоритм подкачки с объектами, вы получите тот же результат, что и последний.

+0

спасибо Крис, я понял. – Wondering

1

второй набор объектов [object x = 1] преобразуется в int, который является типом значений, поскольку ему присваивается int при инициализации, поэтому он обрабатывается как int, который является типом значения.

Если вы запустите следующий фрагмент, вы увидите мою точку.

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

returns: "typeof (Int32)" 

поэтому тип вашего object больше не объект, а Int32, который является типом значения.

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

returns: "false" 
+0

IsByRef не проверяет, является ли тип ссылочным типом или нет - он используется для проверки того, передается ли тип параметра * по * ссылке. Это разные вещи. typeof (object) .IsByRef по-прежнему ложь ... –

+0

спасибо, не знал этого. но не настолько ли неинтуитивно, чтобы это свойство было открыто в классе Type, не должно ли оно быть частью пространства имен Reflection? –

3

Ваш вопрос вводит в заблуждение, и ответ на него на самом деле проще, чем:

В функции подкачки, вы обмениваетесь значения свойств MyProperty в этих классах, а не собственно сами классы. Это было бы легко доказать, если бы у вас было другое свойство в классе MyInt под названием «Имя» или что-то еще. После вызова Swap вы увидите, что свойство Name не изменилось.

Причина, по которой в AnotherSwap ничего интересного не происходит, заключается в том, что вы не передаете типы по ссылке вообще, поэтому присваивания, которые вы выполняете с указателем объекта внутри функции, не изменяют указатели оригинальных объектов из перспектива вызывающего абонента.

Что-то еще следует учитывать, когда вы превращаете 10 в объект, вы фактически боксируете объект, и это то, что вам нужно помнить. При написании дженериков, которые вы хотите вести по-разному для ссылочных и значений, я всегда просто использую «где T: class» для ссылочных типов и «где T: struct» для типов значений. Имена двух функций не могут быть одинаковыми.

Смежные вопросы