表达式<func <object>&gt;的arg数组作为流畅的界面</func <object>的一部分

时间:2013-02-08 13:13:11

标签: c# lambda expression-trees fluent-interface

考虑这样的界面:

new Provider().For(myClass).ExcludeProperties("Height", "Width");

public IEditableStateProvider For(object target) {...}
public IEditableStateProvider ExcludePropertyNames(params string[] propertyNames) {...}

我想将params string[] propertyNames arg替换为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 个答案:

答案 0 :(得分:3)

您应该创建一个通用的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)已被激活,您现在可以在调用{{1}时通过lambda以类型安全的方式访问类型T的属性}。


如果你真的想要非通用版本:

ExcludePropertyNames

但请注意下面的评论。