Массив arg Expression<Func <object >> как часть свободного интерфейса
Рассмотрим такой интерфейс:
new Provider().For(myClass).ExcludeProperties("Height", "Width");
public IEditableStateProvider For(object target) {...}
public IEditableStateProvider ExcludePropertyNames(params string[] propertyNames) {...}
Я хочу заменить params string[] propertyNames
спорить с params Expression<Func<object>>[] propertyNames
так что вместо этого у меня будет следующее.
new Provider().For(myClass).ExcludeProperties(()=>Height, ()=>Width);
Я видел код, похожий на этот, поэтому я думаю, что он должен работать, но я пока не понимаю. Как я могу заставить это работать?
РЕДАКТИРОВАТЬ - делать это без Generics
Вот код из проекта с открытым исходным кодом, который я смотрел, где вывод типов работает без каких-либо обобщений. Я хотел сделать то же самое, но я не вижу, откуда исходит вывод типа (хотя я вижу, что это работает!)
// USAGE (here this is being called from code-behind of a WPF window
private void TrackSelectedTab() {
Services.Tracker.Configure(tabControl)
.AddProperties(() => tabControl.SelectedIndex);
Services.Tracker.ApplyState(tabControl);
}
private void TrackMainWindow() {
Services.Tracker.Configure(this)
.AddProperties(
() => Height,
() => Width,
() => Left,
() => Top,
() => WindowState)
.SetKey("MainWindow")
.SetMode(PersistModes.Automatic);
Services.Tracker.ApplyState(this);
}
// Collab classes
public class SettingsTracker
{
public TrackingConfiguration Configure(object target) {
...
return config;
}
}
public class TrackingConfiguration
{
public TrackingConfiguration AddProperties(params Expression<Func<object>>[] properties) {
...
return this;
}
}
static class Services
{
public static readonly SettingsTracker Tracker = new SettingsTracker(ObjectStore);
}
1 ответ
Вы должны создать общий Provider
класс в дополнение к неуниверсальному, так что вы можете воспользоваться преимуществами вывода типов и безопасности типов:
Интерфейс:
interface IEditableStateProvider<T>
{
IEditableStateProvider<T> For(T target);
IEditableStateProvider<T> ExcludePropertyNames(params Expression<Func<T, object>>[] excludedProperties);
}
Фиктивная реализация:
class Provider<T> : IEditableStateProvider<T>
{
public IEditableStateProvider<T> For(T target)
{
// dummy
return this;
}
public IEditableStateProvider<T> ExcludePropertyNames(params Expression<Func<T, object>>[] excludedProperties)
{
// dummy
return this;
}
}
class Provider
{
// generic factory method to make use of type inference
public static IEditableStateProvider<T> For<T>(T obj)
{
return new Provider<T>().For(obj);
}
}
Использование:
var myClass = new List<object>(); // or whatever
Provider.For(myClass).ExcludePropertyNames(x => x.Count);
Тип T
теперь выводится, когда вы звоните .For(myClass)
и теперь вы можете получить доступ к свойствам типа T
безопасным способом через лямбду при вызове ExcludePropertyNames
,
Если вы действительно хотите неуниверсальную версию:
interface IEditableStateProvider
{
IEditableStateProvider For(object target);
IEditableStateProvider ExcludePropertyNames(params Expression<Func<object>>[] excludedProperties);
}
class Provider : IEditableStateProvider
{
public IEditableStateProvider For(object target)
{
// dummy
return this;
}
public IEditableStateProvider ExcludePropertyNames(params Expression<Func<object>>[] excludedProperties)
{
// dummy
return this;
}
}
var myClass = new List<object>();
new Provider().For(myClass).ExcludePropertyNames(() => myClass.Count);
но, пожалуйста, обратите внимание на мой комментарий ниже.