Доклад со встречи барнаульского сообщества .NET разработчиков, состоявшейся 26 февраля в офисе компании Энтерра (www.enterra.ru)
1 of 27
Download to read offline
More Related Content
Об особенностях использования значимых типов в .NET
1. Об особенностях использования значимых типов в .NET
Андрей Акиньшин
Барнаульское сообщество .NET разработчиков
bug.ineta.ru
www.facebook.com/groups/dotnetbarnaul/
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. Изменяемые значимые типы
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. Изменяемые значимые типы
Будут проблемы:
// 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. Изменяемые значимые типы
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. Изменяемые значимые типы
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. Упаковка и распаковка
// 1
var arrayList = new ArrayList();
var p = new Point();
arrayList.Add(p);
// Упаковка
p = (Point) arrayList[0];
// Распаковка
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. Упаковка и распаковка
// 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. Упаковка и распаковка
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. Упаковка и распаковка
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);
15. Конструкторы по умолчанию
• .NET поддерживает конструкторы по умолчанию для
структур
• А C# — нет
• Но мы всё равно создадим структуру с конструктором
по умолчанию, которую назовём MyStruct
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. GetHashCode()
• Быстрая версия
(Структура не имеет ссылочных полей, а между её
полями нет свободного места)
Используем Xor каждых 4 байта структуры
• Медленная версия
Используем GetHashCode первого нестатичного поля
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
20. Equals()
var redName = Color.Red;
var redArgb = Color.FromArgb(255, 255, 0, 0);
Console.WriteLine(redName == redArgb);
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. Размещение в памяти
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)));
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.