【问题标题】:Is there any way to infer an Action type, or a full Action?有什么方法可以推断出一个动作类型,或者一个完整的动作?
【发布时间】:2010-12-05 19:04:54
【问题描述】:

我发现自己(也)经常使用如下结构:

class MyClass
{
    public TypeA ObjectA;
    public TypeB ObjectB;
    public TypeC ObjectC;
    public List<TypeD> ListOfObjectD = new List<TypeD>();

    public void DoSmth()
    {
        return SomeConstruct(
            /*...*/
            new Setter<TypeA>(a => ObjectA = a), // these are the
            new Setter<TypeB>(b => ObjectB = b), // things I'm trying
            new Setter<TypeC>(c => ObjectC = c), // to make shorter
            new Setter<TypeD>(d => ListOfObjectD.Add(d)),
            /*...*/
        );
    }
}
class Setter<T>
{
    public Action<T> Action;

    public Setter(Action<T> action)
    {
        Action = action;
    }
}

Setter 类有什么方法可以推断出 Action 的类型并通过某种方式仅传递 Member 来创建标准的(T obj) =&gt; Member = obj Action?我正在考虑类似的事情:

new Setter(ObjectA)

这当然不是有效的语法,但应该让您了解我想要实现的目标。我在我的代码中确实使用了这个构造 数百 时间,所以代码 这个小小的改变所节省的将是巨大的。


编辑:添加了 TypeD 示例。部分

new Setter<TypeD>(d => ListOfObjectD.Add(d))

可以简化为

new Setter<TypeD>(ListOfObjectD.Add)

这太棒了,因为它减少了冗余代码。如果也只能推断出&lt;TypeD&gt;,那将是完美的。我正在为其他人寻找类似的东西。

@Lazarus - 基本上目的是返回设置器,因此其他对象可以设置类的某些成员(或者它可以执行 Action 中定义的其他事情)而无需访问类本身,仅设置器对象。完整的原因列表很长而且令人费解,但程序的结构就像一个魅力,我怀疑需要改变(当然,这个例子被简化了,并没有真正的意义)。


编辑 2:我找到了一种简化 List 的好方法:

static class SetterHelper
{
    public static Setter<T> GetSetter<T>(this List<T> list)
    {
        return new Setter<T>(list.Add);
    }
}

现在我可以用这个了:

ListOfObjectD.GetSetter()

效果很好!为什么我不能直接对 T 做同样的事情?我试过这个:

static class SetterHelper
{
    public static Setter<T> GetSetter<T>(this T item)
    {
        return new Setter<T>(t => item = t); // THIS DOESN'T SET THE PASSED MEMBER
    }
}

当然它不会按预期工作,因为它会设置项目,但不会设置传递的成员。我尝试将ref 添加为(ref this T item),但它不会编译:(...这将是完美的。

【问题讨论】:

  • 很抱歉我无法测试这个,因为我没有在我的 Windows 分区上安装 Visual Studio 但你能做 public void DoSmth(Object ObjectType) 然后 typeof(ObjectType) 来获得创建对象时的对象类型?
  • 我在这里遗漏了一些东西,这个构造的目的是什么?我的经验是,当事情变得过于复杂时,我通常会误解问题空间和/或语言结构。如果有人能解释这个结构的作用和原因,我将不胜感激。
  • 我的经验是,当人们发布示例时,他们通常会删除无关代码,以便他们可以专注于问题。如果没有上下文,其他程序员可能会混淆他们为什么要这样做。当然,确保尽可能有效地解决问题很有用,但我觉得这涉及到设计。如果问题不是专门针对设计的,那么我只是尝试帮助他们解决手头的问题。
  • 哦,我刚刚阅读了您的最后一次编辑...也许这对您有帮助? --> stackoverflow.com/questions/3653854/…
  • 为什么不将GetSetter实现为普通方法(不是扩展方法),以ref T item为参数。您可以缩短方法和静态类的名称以避免重复输入.实际上,在同一个命名空间中同时拥有Setter 静态类和Setter&lt;T&gt; 类是合法的,所以你可以写Settter.Get(ref Object A)

标签: c# types action type-inference


【解决方案1】:

我能提供给你的最好的语法如下:

Setter.For( () => ObjectA );

使用这个帮助类

static class Setter
{
    public static Setter<T> For<T>(Expression<Func<T>> e)
    {
        ParameterExpression[] args = { Expression.Parameter(((e.Body as MemberExpression).Member as FieldInfo).FieldType) };
        Action<T> s = Expression.Lambda<Action<T>>(Expression.Assign(e.Body, args[0]), args).Compile();

        return new Setter<T>(s);
    }
}

【讨论】:

  • Mmh... 听起来类似于这个答案 --> stackoverflow.com/questions/3653854/…
  • @digEmAll:是的,它在很多方面都很相似。直到我在 Visual Studio 中将所有内容都整理出来后才看到您的链接。
  • 对性能不太友好,但无论如何感谢您的想法。
  • 是的,我可能应该提到...表达式树与反射相比是有效的,但与预编译代码相比却没有。当然,一旦创建了委托,它会一样快,但初始设置过程不是。
猜你喜欢
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 2017-04-14
  • 2013-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-18
相关资源
最近更新 更多