27
Об особенностях использования значимых типов в .NET Андрей Акиньшин Барнаульское сообщество .NET разработчиков bug.ineta.ru www.facebook.com/groups/dotnetbarnaul/

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

Embed Size (px)

Citation preview

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

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

Андрей Акиньшин

Барнаульское сообщество .NET разработчиков

bug.ineta.ruwww.facebook.com/groups/dotnetbarnaul/

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

Структуры

• Копирование по значению• Поддержка boxed и unboxed формы• Всегда инициализированы• Методы из Equals, GetHashCode из System.ValueType• Не могут быть базовыми типами

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

Изменяемые значимые типы

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

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

Изменяемые значимые типы

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

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

Изменяемые значимые типы

Будут проблемы:// 1. Propertypublic class Circle{

public Point Center { get; set; }}// 2. Readonly fieldpublic class Circle{

public readonly Point Center = new Point();}// 3. IListvar points = new List<Point>();

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

Изменяемые значимые типы

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

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

Изменяемые значимые типы

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

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

Упаковка и распаковка

// 1var arrayList = new ArrayList();var p = new Point();arrayList.Add(p); // Упаковкаp = (Point) arrayList[0]; // Распаковка

// 2Int32 x = 5;Object o = x; // УпаковкаInt16 y = (Int16) o; // InvalidCastExceptionInt16 z = (Int16)(Int32) o; // Распаковка и приведение

// 3Int32 x = 1;Object y = x;x = 2;Console.WriteLine(x + "/" + (Int32)y);// "2/1"

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

Упаковка и распаковка

// 1var arrayList = new ArrayList();var p = new Point();arrayList.Add(p); // Упаковкаp = (Point) arrayList[0]; // Распаковка

// 2Int32 x = 5;Object o = x; // УпаковкаInt16 y = (Int16) o; // InvalidCastExceptionInt16 z = (Int16)(Int32) o; // Распаковка и приведение

// 3Int32 x = 1;Object y = x;x = 2;Console.WriteLine(x + "/" + (Int32)y);// "2/1"

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

Упаковка и распаковка

// 1var arrayList = new ArrayList();var p = new Point();arrayList.Add(p); // Упаковкаp = (Point) arrayList[0]; // Распаковка

// 2Int32 x = 5;Object o = x; // УпаковкаInt16 y = (Int16) o; // InvalidCastExceptionInt16 z = (Int16)(Int32) o; // Распаковка и приведение

// 3Int32 x = 1;Object y = x;x = 2;Console.WriteLine(x + "/" + (Int32)y);// "2/1"

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

Упаковка и распаковка

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

}

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

Упаковка и распаковка

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

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

Конструкторы по умолчанию

• .NET поддерживает конструкторы по умолчанию дляструктур

• А C# — нет• Но мы всё равно создадим структуру с конструкторомпо умолчанию, которую назовём MyStruct

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

Конструкторы по умолчанию

• .NET поддерживает конструкторы по умолчанию дляструктур

• А C# — нет

• Но мы всё равно создадим структуру с конструкторомпо умолчанию, которую назовём MyStruct

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

Конструкторы по умолчанию

• .NET поддерживает конструкторы по умолчанию дляструктур

• А C# — нет• Но мы всё равно создадим структуру с конструкторомпо умолчанию, которую назовём MyStruct

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

Конструкторы по умолчанию

// Вспомогательные методы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];

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

GetHashCode()

• Быстрая версия(Структура не имеет ссылочных полей, а между еёполями нет свободного места)Используем Xor каждых 4 байта структуры

• Медленная версияИспользуем GetHashCode первого нестатичного поля

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

GetHashCode()

var a1 = new KeyValuePair<int, int>(1, 2);var a2 = new KeyValuePair<int, int>(1, 3);Console.WriteLine(a1.GetHashCode()); // 1033533110Console.WriteLine(a2.GetHashCode()); // 1033533111

var b1 = new KeyValuePair<int, string>(1, "x");var b2 = new KeyValuePair<int, string>(1, "y");Console.WriteLine(b1.GetHashCode()); // -1888265882Console.WriteLine(b2.GetHashCode()); // -1888265882

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

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;

}

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

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;

}}

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

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;

}}

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

Размещение в памяти

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

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

Размещение в памяти

[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

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

Размещение в памяти

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.

}}

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

Хорошие книжки

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

Блоги

• 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/

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

Спасибо за внимание!