Страницы

Поиск по вопросам

пятница, 2 ноября 2018 г.

Добавить поле к существующему классу (Attached Properties)

Есть класс Line c полями Begin, End. Теперь нужно чтобы у класса Line была толщина. Реализую с помощью методов расширения GetDepth и SetDepth. Как это можно сделать?
namespace Geometry { public class Line { public Point Begin; public Point End; } }
namespace GeometryPaint { public static class SegmentExtension { public static int GetDepth (this Line line) { //TODO } public static void SetDepth (this Line line, int depth) { //TODO } }
public static class SegmentExtension { static void Main() { var lineOne = new Line { Begin = new Point(0,0), End = new Point(3,3)}; var lineTwo = new Line { Begin = new Point(4,2), End = new Point(7,9)}; lineOne.SetDepth(5); lineTwo.SetDepth(32); int depthLineTwo = lineTwo.GetDepth(); int depthLineOne = lineOne.GetDepth(); } } }


Ответ

То, что вы хотите, называется Attached Properties. В C# нет родного (на уровне синтаксиса) механизма их реализации. Но в стандартной библиотеке есть класс ConditionalWeakTable, который позволяет хранить значения "дополнительных" свойств, не продлевая при этом жизнь объектов-ключей. Реализация attached properties через него будет выглядеть примерно так:
using System.Runtime.CompilerServices;
namespace Geometry { public static class SegmentExtensions { // TValue должен быть reference type, так что костыль в виде каста к object private readonly static ConditionalWeakTable _depthValues = new ConditionalWeakTable();
public static int GetDepth(this Line line) { return (int)_depthValues.GetValue(line, (l) => 0); } public static void SetDepth(this Line line, int depth) { _depthValues.Remove(line); // возможно, затрайкетчить в случае работы из нескольких потоков _depthValues.Add(line, depth); } }
public static class Startup { static void Main() { var lineOne = new Line { Begin = new Point ( 0, 0 ), End = new Point ( 3, 3 ) }; var lineTwo = new Line { Begin = new Point ( 4, 2 ), End = new Point ( 7, 9 ) }; lineOne.SetDepth(5); lineTwo.SetDepth(32); int depthLineTwo = lineTwo.GetDepth(); int depthLineOne = lineOne.GetDepth(); } }
public class Line { public Point Begin; public Point End; }
public class Point { private int v1; private int v2;
public Point(int v1, int v2) { this.v1 = v1; this.v2 = v2; } }
}

Комментариев нет:

Отправить комментарий