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

Post on 12-Jul-2015

2.280 Views

Category:

Education

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

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

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

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

Структуры

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

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

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

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

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

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

Будут проблемы:// 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>();

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

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

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

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

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

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

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

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

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

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

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

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

}

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

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

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

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

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

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

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

• А C# — нет

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

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

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

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

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

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

GetHashCode()

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

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

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

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;

}

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;

}}

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;

}}

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

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

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

[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

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

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.

}}

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

Блоги

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

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

top related