#c# #properties #metaprogramming #accessor
#c# #свойства #метапрограммирование #средство доступа
Вопрос:
Я новичок в c # и ломал голову над этим пару дней. В принципе, я хочу создать тип свойства с логикой получения и установки, делегированной базовому типу, к которому принадлежит этот параметр.
Это всего лишь одно приложение: свойство, значение которого задается, скажем, реестром или каким-либо конфигурационным файлом.
- Обработчик свойств в get будет выполнять что-то вроде проверки кэшированного значения (или нет), извлекать значение, если оно не кэшировано, кэшировать значение (или нет) и возвращать его.
- Поведение установщика позволило бы только обработчику свойств устанавливать значение (если это возможно).
Есть предложения? Я думал об использовании DefaultPropertyAttribute
, но я не совсем понимаю, как не писать всю необходимую логику с каждым средством доступа.
Похоже, это то, что я хочу: http://www.sharpcrafters.com/postsharp
«Писать меньше кода» Да. Все в порядке.
Ответ №1:
Я этим не горжусь:
public abstract class HorribleBaseType
{
private Lazy<string> _connectionString;
private Action<string> _connectionStringSetter;
private Func<string> _connectionStringGetter;
public HorribleBaseType(
Func<string> connectionStringGetter,
Action<string> connectionStringSetter)
{
_connectionStringGetter = connectionStringGetter;
_connectionStringSetter = connectionStringSetter;
_connectionString = new Lazy<string>(connectionStringGetter);
}
public string ConnectionString
{
get { return _connectionString.Value; }
set
{
_connectionStringSetter(value);
_connectionString = new Lazy<string>(_connectionStringGetter);
}
}
}
public class HorribleType : HorribleBaseType
{
public HorribleType()
: base(() => MyConfiguration.ConnectionString,
(v) => MyConfiguration.ConnectionString = v) { }
}
100% непроверенный.
ОБНОВИТЬ Используя комбинацию вышеприведенного и ответа @hunter, вы могли бы сделать что-то вроде:
public class DelegateProperty<T>
{
#region Fields
private readonly Func<T> _getter;
private readonly Action<T> _setter;
private Lazy<T> _lazy;
#endregion
#region Constructors
public DelegateProperty(Func<T> getter, Action<T> setter)
{
_getter = getter;
_setter = setter;
_lazy = new Lazy<T>(getter);
}
#endregion
#region Properties
public T Value
{
get { return _lazy.Value; }
set
{
_setter(value);
_lazy = new Lazy<T>(_getter);
}
}
#endregion
#region Operators
public static implicit operator T(DelegateProperty<T> prop)
{
return prop.Value;
}
#endregion
}
С этим теперь вы можете сделать что-то вроде:
class Program
{
static void Main(string[] args)
{
string name = "Matt";
var prop = new DelegateProperty<string>(
() => name,
value => name = value);
var test = new Test(prop);
Console.WriteLine(test.Name);
test.Name = "Ben";
Console.WriteLine(name);
Console.ReadKey();
}
}
public class Test
{
private readonly DelegateProperty<string> NameProperty;
public Test(DelegateProperty<string> prop)
{
NameProperty = prop;
}
public string Name
{
get { return NameProperty; }
set { NameProperty.Value = value; }
}
}
Ответ №2:
Используя этот дурацкий класс:
public class Property<T>
{
Func<T> _func;
T _value;
bool _fetched;
public Property(Func<T> func)
{
_func = func;
}
public T Value
{
get
{
if (!_fetched)
{
_value = _func();
_fetched = true;
}
return _value;
}
set { _value = value; }
}
}
вы можете сделать что-то вроде этого:
public class TestClass
{
Property<int> _propertyInt;
public int MyInt
{
get { return _propertyInt.Value; }
set { _propertyInt.Value = value; }
}
Property<string> _propertyString;
public string MyString
{
get { return _propertyString.Value; }
set { _propertyString.Value = value; }
}
}
Конечно, это не будет обрабатывать каждый случай, но это может вывести вас на «правильный» путь…
Комментарии:
1. Но у вас все равно был бы установщик общего назначения, не ограниченный ожидаемым типом поведения. По крайней мере, вы понимаете, что идея не в том, чтобы использовать базовый класс с таким поведением. Я не совсем против идеи общих установщиков, хотя и исхожу из опыта написания сценариев.