Вопрос по state, dictionary, c#, extension-methods, reference – Сохранение состояния в методе расширения

10

Команда C # ранее рассматривала возможность добавления свойств расширения, событий и т. Д. В C #.

Пер Эрик Липперт:

http://blogs.msdn.com/b/ericlippert/archive/2009/10/05/why-no-extension-properties.aspx

Однако для того, чтобы эти функции были полезны, они должны были бы иметь возможность хранить какой-то новый тип состояния с объектом. Кажется, что единственный способ сделать это - использовать словарь и связать каждый экземпляр объекта с каким-либо дополнительным состоянием.

Было бы полезно, если бы можно было скопировать эту функцию "вручную" создав свой собственный словарь (и, возможно, получить / установить методы расширения). Однако для того, чтобы связать определенныйinstance объекта с некоторым состоянием, вам нужно будет хешировать фактическоеreference к объекту. На другом языке вы могли бы сделать это, хэшируя место в памяти, однако в C # это не гарантируется постоянным, и использование небезопасного кода для реализации этой функции в любом случае далеко от идеала.

Кто-нибудь знает, возможно ли получить некоторую хешируемую ссылку на объект, которая не изменяется при изменении внутреннего состояния объекта? Очевидно, существует некоторый внутренний механизм для отслеживания отдельных объектов независимо от их местоположения в памяти, но я не уверен, что на него воздействует пользовательский код.

Примечание: простое хеширование самого объекта вообще не будет работать, поскольку GetHashCode () зависит от того, не находится ли внутреннее состояние объектаwhich object это.

Спасибо за понимание.

Тьфу, мне нравятся методы расширения, потому что они не имеют отношения к состоянию объекта и являются всего лишь синтаксическим сахаром, я боюсь, что что-то еще действительно слишком сильно стирает строки ... Тем не менее, это интересная мысль, конечно... James Michael Hare

Ваш Ответ

2   ответа
0

Свойства хранятся в словаре, который использует слабые ссылки на объекты в качестве ключей, и словарь с парами строк-объектов для хранения свойств и их значений.

Чтобы установить, получить или удалить свойства для объекта, поиск объекта осуществляется по слабым ссылкам в словаре.

Там может быть два способа избавиться от неиспользуемых свойств:

check the IsAlive of the weak reference, and remove the entry in the dictionary if false implement IDisposable in the "extendable" objects and call an extension method that removes the properties on the object being disposed.

Я включил необязательный блок using в пример кода, чтобы вы могли отладить и посмотреть, как Dispose вызываетRemoveProperties метод расширения. Это, конечно, необязательно, и метод вызывается, когда объект является GC-ed.

Рабочий образец идеи с использованием WeakReference, статических словарей и IDisposable.

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            using (PropertyLessClass plc = new PropertyLessClass())
            {
                plc.SetProperty("age", 25);
                plc.SetProperty("name", "John");
                Console.WriteLine("Age: {0}", plc.GetProperty("age"));
                Console.WriteLine("Name: {0}", plc.GetProperty("name"));
            }
            Console.ReadLine();
        }
    }
}

public class PropertyLessClass : IDisposable
{
    public void Dispose()
    {
        this.DeleteProperties();
    }
}

public static class PropertyStore
{
    private static Dictionary<WeakReference, Dictionary<string, object>> store
        = new Dictionary<WeakReference, Dictionary<string, object>>();

    public static void SetProperty(this object o, string property, object value)
    {
        var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o);
        if (key == null)
        {
            key = new WeakReference(o);
            store.Add(key, new Dictionary<string, object>());
        }
        store[key][property] = value;
    }

    public static object GetProperty(this object o, string property)
    {
        var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o);
        if (key == null)
        {
            return null; // or throw Exception
        }
        if (!store[key].ContainsKey(property))
            return null; // or throw Exception
        return store[key][property];
    }

    public static void DeleteProperties(this object o)
    {
        var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o);
        if (key != null)
        {
            store.Remove(key);
        }
    }
}
@SLaks. Во-первых, это только доказательство концепции. Вторая «преждевременная оптимизация - корень всего зла». Это действительно достаточно медленно, чтобы сделать его необходимым для оптимизации? Это должно быть собрано перед выполнением оптимизации. В-третьих, как бы вы точно реализовали словарь и IEqualityComparer, чтобы сделать его быстрее? Я не могу понять вашу идею.
Я думаю, я сделаю. Я добавил текст в свой ответ.
Использование словаря, как это на самом деле делает этот кодslower, Вместо этого вы должны передать пользовательскийIEqualityComparer<WeakReference>.
Я думаю, вы неправильно поняли вопрос. MgSam
Спасибо за ответ. Одна из проблем этого кода заключается в том, что он использует слабо типизированные магические строки для представления имен свойств. Используя методы расширения для самого класса, вы можете создавать методы get / set, которые не страдают от этой проблемы. MgSam
13
@MgSam: комментарии в источнике говорят, что он был добавлен для DLR.
Вот это да. Другой случай «После 10 лет использования C # я все еще обнаруживаю вещи». Благодарю.
Интересно, был ли этот класс создан специально для свойств расширения, которые были вырезаны из C # 4.0. MgSam
@KooKiz: попробуйтеPluralizationService учебный класс
Я также поражен тем, что не видел этого раньше. Похоже, что это работает, приводя к объекту, а затем вызывая RuntimeHelpers.GetHashCode (), (что делает магию во время выполнения). Знаете ли вы последствия использования этого класса для производительности? MgSam

Похожие вопросы