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

382
29 июля 2017, 03:17

Есть класс 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();
           }
    }
}
Answer 1

То, что вы хотите, называется Attached Properties. В C# нет родного (на уровне синтаксиса) механизма их реализации. Но в стандартной библиотеке есть класс ConditionalWeakTable<TKey, TValue>, который позволяет хранить значения "дополнительных" свойств, не продлевая при этом жизнь объектов-ключей. Реализация attached properties через него будет выглядеть примерно так:

using System.Runtime.CompilerServices;
namespace Geometry
{
    public static class SegmentExtensions
    {
        // TValue должен быть reference type, так что костыль в виде каста к object
        private readonly static ConditionalWeakTable<Line, object> _depthValues =
            new ConditionalWeakTable<Line, object>();
        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;
        }
    }
}
READ ALSO
Как узнать что были изменения значений во вложенных контролах формы?

Как узнать что были изменения значений во вложенных контролах формы?

Есть форма, на ней размещены контроллы (textbox, checkbox

330
Сократить множетсво if-else

Сократить множетсво if-else

Есть метод который принимает строку и в зависимости от строки возвращает кортеж Tuple с одним int и одним string значениемПроблема в том, что если...

392
Получить имя столбца в DataTable

Получить имя столбца в DataTable

Выбираю адаптером таблицу из БДПримерно так :

334
Почему некорректно работает компонент Navs (Bootstrap 4) в связке с Vue.js?

Почему некорректно работает компонент Navs (Bootstrap 4) в связке с Vue.js?

Во Vue компоненте есть массив pages, каждый элемент которого представляет из себя хеш

313