Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Об особенностях использования значимых типов в .NET

3,096 views

Published on

Доклад со встречи барнаульского сообщества .NET разработчиков, состоявшейся 26 февраля в офисе компании Энтерра (www.enterra.ru)

Published in: Education
  • Be the first to comment

Об особенностях использования значимых типов в .NET

  1. 1. Об особенностях использования значимых типов в .NET Андрей Акиньшин Барнаульское сообщество .NET разработчиков bug.ineta.ru www.facebook.com/groups/dotnetbarnaul/
  2. 2. Структуры • • • • • Копирование по значению Поддержка boxed и unboxed формы Всегда инициализированы Методы из Equals, GetHashCode из System.ValueType Не могут быть базовыми типами
  3. 3. Изменяемые значимые типы public struct Point { public int X, Y; public void Move(int dx, int dy) { X += dx; Y += dy; } } public class Circle { public Point Center; // Поле } var circle = new Circle(); circle.Center = new Point { X = 0, Y = 0 }; circle.Center.Move(5, 5); Console.WriteLine(circle.Center.X);
  4. 4. Изменяемые значимые типы public struct Point { public int X, Y; public void Move(int dx, int dy) { X += dx; Y += dy; } } public class Circle { public Point Center { get; set; } // Свойство } var circle = new Circle(); circle.Center = new Point { X = 0, Y = 0 }; circle.Center.Move(5, 5); Console.WriteLine(circle.Center.X);
  5. 5. Изменяемые значимые типы Будут проблемы: // 1. Property public class Circle { public Point Center { get; set; } } // 2. Readonly field public class Circle { public readonly Point Center = new Point(); } // 3. IList var points = new List<Point>();
  6. 6. Изменяемые значимые типы public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator var x = new { Items = new List<int> { 1, 2, 3 }.GetEnumerator() }; while (x.Items.MoveNext()) Console.WriteLine(x.Items.Current);
  7. 7. Изменяемые значимые типы struct Disposable : IDisposable { public bool Disposed { get; private set; } public void Dispose() { Disposed = true; } } var d = new Disposable(); using (d) { // Some code } Console.WriteLine(d.Disposed);
  8. 8. Упаковка и распаковка // 1 var arrayList = new ArrayList(); var p = new Point(); arrayList.Add(p); // Упаковка p = (Point) arrayList[0]; // Распаковка
  9. 9. Упаковка и распаковка // 1 var arrayList = new ArrayList(); var p = new Point(); arrayList.Add(p); // Упаковка p = (Point) arrayList[0]; // Распаковка // 2 Int32 x = 5; Object o = x; // Упаковка Int16 y = (Int16) o; // InvalidCastException Int16 z = (Int16)(Int32) o; // Распаковка и приведение
  10. 10. Упаковка и распаковка // 1 var arrayList = new ArrayList(); var p = new Point(); arrayList.Add(p); // Упаковка p = (Point) arrayList[0]; // Распаковка // 2 Int32 x = 5; Object o = x; // Упаковка Int16 y = (Int16) o; // InvalidCastException Int16 z = (Int16)(Int32) o; // Распаковка и приведение // 3 Int32 x = 1; Object y = x; x = 2; Console.WriteLine(x + "/" + (Int32)y);// "2/1"
  11. 11. Упаковка и распаковка interface IChangeable { void Change(int x, int y); } struct Point : IChangeable { public int X, Y; public void Change(int x, int y) { X = x; Y = y; } public override string ToString() { return X + "," + Y; } }
  12. 12. Упаковка и распаковка var p = new Point {X = 1, Y = 1}; Console.WriteLine(p); p.Change(2, 2); Console.WriteLine(p); Object o = p; Console.WriteLine(o); ((Point) o).Change(3, 3); Console.WriteLine(o); ((IChangeable)p).Change(4, 4); Console.WriteLine(p); ((IChangeable)o).Change(5, 5); Console.WriteLine(o);
  13. 13. Конструкторы по умолчанию • .NET поддерживает конструкторы по умолчанию для структур
  14. 14. Конструкторы по умолчанию • .NET поддерживает конструкторы по умолчанию для структур • А C# — нет
  15. 15. Конструкторы по умолчанию • .NET поддерживает конструкторы по умолчанию для структур • А C# — нет • Но мы всё равно создадим структуру с конструктором по умолчанию, которую назовём MyStruct
  16. 16. Конструкторы по умолчанию // Вспомогательные методы static T CreateAsDefault<T>() { return default(T); } static T CreateWithNew<T>() where T : new() { return new T(); } // Вызывается var m = Activator.CreateInstance(typeof(MyStruct)); var m = new MyStruct(); // Не вызывается var m = default(MyStruct); var m = CreateWithNew<MyStruct>(); var m = CreateAsDefault<MyStruct>(); var array = new MyStruct[100];
  17. 17. GetHashCode() • Быстрая версия (Структура не имеет ссылочных полей, а между её полями нет свободного места) Используем Xor каждых 4 байта структуры • Медленная версия Используем GetHashCode первого нестатичного поля
  18. 18. GetHashCode() var a1 = new KeyValuePair<int, int>(1, 2); var a2 = new KeyValuePair<int, int>(1, 3); Console.WriteLine(a1.GetHashCode()); // 1033533110 Console.WriteLine(a2.GetHashCode()); // 1033533111 var b1 = new KeyValuePair<int, string>(1, "x"); var b2 = new KeyValuePair<int, string>(1, "y"); Console.WriteLine(b1.GetHashCode()); // -1888265882 Console.WriteLine(b2.GetHashCode()); // -1888265882
  19. 19. Equals() public override bool Equals (Object obj) { // ... FieldInfo[] thisFields = thisType.GetFields( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); for (int i=0; i<thisFields.Length; i++) { thisResult = ((RtFieldInfo)thisFields[i]). InternalGetValue(thisObj,false); thatResult = ((RtFieldInfo)thisFields[i]). InternalGetValue(obj, false); if (thisResult == null) { if (thatResult != null) return false; } else if (!thisResult.Equals(thatResult)) return false; } return true; }
  20. 20. Equals() var redName = Color.Red; var redArgb = Color.FromArgb(255, 255, 0, 0); Console.WriteLine(redName == redArgb);
  21. 21. Equals() var redName = Color.Red; var redArgb = Color.FromArgb(255, 255, 0, 0); Console.WriteLine(redName == redArgb); public struct Color { private readonly long value; private readonly string name; private readonly short knownColor, state; public static bool operator ==(Color left, Color right) { if (left.value == right.value && left.state == right.state && left.knownColor == right.knownColor) { if (left.name == right.name) return true; if (left.name == (object) null || right.name == (object) null) return false; return left.name.Equals(right.name); } return false; } }
  22. 22. Размещение в памяти public struct S1 { public byte Byte1; public int Int1; } public struct S2 { public byte Byte1; public byte Byte2; public byte Byte3; public byte Byte4; public int Int1; } Console.WriteLine(Marshal.SizeOf(typeof(S1))); Console.WriteLine(Marshal.SizeOf(typeof(S2)));
  23. 23. Размещение в памяти [StructLayout(LayoutKind.Explicit)] struct MyStruct { [FieldOffset(0)] public Int16 Value; [FieldOffset(0)] public Byte LowByte; } var s = new MyStruct(); s.Value = 256 + 100; Console.WriteLine(s.LowByte); // 100
  24. 24. Размещение в памяти namespace System.Drawing { public struct Color { /** * Shift count and bit mask for A, R, G, B * components in ARGB mode! */ private const int ARGBAlphaShift = 24; private const int ARGBRedShift = 16; private const int ARGBGreenShift = 8; private const int ARGBBlueShift = 0; /// /// /// /// /// /// /// } } WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! We can never change the layout of this class (adding or removing or changing the order of member variables) if you want to be compatible v1.0 version of the runtime This is so that we can push into the runtime a custom marshaller for OLE_COLOR to Color.
  25. 25. Хорошие книжки
  26. 26. Блоги • http://msdn.microsoft.com/magazine/ • http://www.rsdn.ru/ • http://blogs.msdn.com/b/ericlippert/ • http://sergeyteplyakov.blogspot.ru/ • http://timyrguev.blogspot.ru/ • http://aakinshin.blogspot.ru/
  27. 27. Спасибо за внимание!

×