Итак, вот надуманный пример того, что я хочу улучшить или подтвердить.
Я использую (my / i) BATIS.NET (облегченный каркас ORM / data mapper) и чтоУ меня есть класс со статической ссылкой на каждый из картографов для базы данных.Это прекрасно работает, но повторений так много, что я подумал, что может быть возможность значительно упростить код.Класс в настоящее время выглядит так:
public sealed class MyRepository
{
private static string _connectionString;
private volatile static TableAbcMapper _tableAbcMapper;
private volatile static TableXyzMapper _tableXyzMapper;
// and about 30 more of these
private MyRepository()
{
}
public static void Init(string connectionString)
{
_connectionString = connectionString;
}
public static string ConnectionString
{
get { return _connectionString; }
}
public static TableAbcMapper TableAbc
{
get
{
if (_tableAbcMapper == null)
{
lock (typeof(TableAbcMapper))
{
if (_tableAbcMapper == null)
{
_tableAbcMapper = new TableAbcMapper(_connectionString);
}
}
}
return _tableAbcMapper;
}
}
public static TableXyzMapper TableXyz
{
get
{
if (_tableXyzMapper == null)
{
lock (typeof(TableXyzMapper))
{
if (_tableXyzMapper == null)
{
_tableXyzMapper = new TableXyzMapper(_connectionString);
}
}
}
return _tableXyzMapper;
}
}
// and about 30 more of these readonly properties
}
Каждый раз, когда я добавляю или удаляю таблицу из базы данных, я получаю добавить поле private volatile static
и это большое уродливое свойство singleton-y в класс MyRepository
,Моей первой идеей было сделать так, чтобы свойства вызывали универсальную экземплярную функцию внутри класса;что-то похожее на:
private static void InitMapper<TMapper>(TMapper instance) where TMapper : MyMapper
{
lock (typeof(TMapper))
{
if (instance == null)
{
instance = Activator.CreateInstance(typeof(TMapper),
new object[] { _connectionString }) as TMapper;
}
}
}
Тогда число публичных получателей может быть немного уменьшено до:
public static TableXyzMapper TableXyz
{
get
{
if (_tableXyzMapper == null)
{
InitMapper<TableXyzMapper>(_tableXyzMapper);
}
return _tableXyzMapper;
}
}
Но я не знаю, является ли идеальной идеей обходить изменчивые поляи использование ref
или out
с изменяемыми полями - это нет-нет, и, кроме того, это не сильно уменьшает объем кода.
Что я хотел бы сделать, так это полностью изменить класс MyRepository
, чтобы он не имел закрытых полей и общедоступных получателей, и использовал отражение для немедленной инициализации всех отображателей вместо их ленивой загрузки.,Мне не пришлось бы менять код, использующий класс MyRepository
, так как он выглядел бы точно так же, но под капотом это было бы немного иначе:
public sealed class MyRepository
{
private MyRepository()
{
}
public volatile static TableAbcMapper TableAbc = null;
public volatile static TableXyzMapper TableXyz = null;
public static void Init(string connectionString)
{
foreach (var fieldInfo in typeof(MyRepository).GetFields(BindingFlags.Static))
{
if (fieldInfo.GetValue(new MyRepository()) == null)
{
lock (fieldInfo.FieldType)
{
if (fieldInfo.GetValue(new MyRepository()) == null)
{
fieldInfo.SetValue(new MyRepository(),
fieldInfo.FieldType.GetConstructor(new Type[] { typeof(string) })
.Invoke(new object[] { connectionString }));
}
}
}
}
}
}
ТеперьЕдинственное обслуживание, которое я должен выполнить, когда новые таблицы добавляются в базу данных, - это добавить для нее новое поле public volatile static
, а остальное позаботится об отражении.
Несколько вопросов, которые у меня естьс этим подходом:
- Является ли этот подход функционально эквивалентным исходному классу?
- Существует ли какая-либо опасность в определении изменчивых переменных с помощью отражения?
- он так же удобен для чтения, как и исходный класс (при условии, что все это прокомментировано)?
Наконец, если этот вопрос лучше подходит для сайта Code Review , я за то, чтобыон мигрировал (моды!).