委托作为第一个参数一个扩展方法 [英] Delegate as first param to an Extension Method

查看:133
本文介绍了委托作为第一个参数一个扩展方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

夫人和绅士,



我最近尝试这个实验:

 静态类TryParseExtensions 
{
公共委托布尔TryParseMethod< T>(字符串s,出牛逼maybeValue);
公共静态T' OrNull< T>(这TryParseMethod< T> tryParser,字符串s)其中T:结构
{$ B $(B T)的结果;
返回tryParser(S,出结果)? (T?)结果:空;
}
}

//编译错误'int.TryParse(字符串,OUT INT)是一个方法,它是不是在给定上下文中有效
变种结果= int.TryParse.OrNull(1); // int.TryParse.OrNull&所述; INT>(1);不工作或者

//编译器错误:类型不能infered ....为什么?
变种结果2 = TryParseExtensions.OrNull(int.TryParse,2);

//将按预期
变种result3 = TryParseExtensions.OrNull&所述; INT>(int.TryParse,3);
变种result4 =((TryParseExtensions.TryParseMethod&所述; INT>)int.TryParse).OrNull(4);



我不知道两件事情:




  • 为什么编译器不能推断出INT类型参数?


  • 我是否理解正确的扩展方法不获得发现的委托类型,因为我想他们不是那种类型的真(而是一个方法),只有正好匹配代表签名?作为这样的铸造解决这个问题。会是infeasable使方案1的工作(不是这一个具体的过程,但在一般)?我从一个语言/编译器的角度进行猜测,它实际上是有用的,还是我只是(试图)在这里疯狂地滥用的东西呢?




期待一些启发。日Thnx


解决方案

您有一些问题在这里。 (今后我会建议,当你有多个问题,将它们分割成多个问题,而不是一个发布在它的几个问题。你可能会得到更好的反应)




为什么编译器不能推断在INT类型的参数:




  TryParseExtensions.OrNull(int.TryParse,2); 



好问题。而不是答案,在这里,我是指你我2007年的文章这就解释了为什么这并没有在工作C#3.0:



http://blogs.msdn .COM / b / ericlippert /存档/ 2007/11/05 / C-3-0收益型推断,不 - 不工作的人组成的,groups.aspx



总结:从根本上是有鸡还是先有蛋的问题在这里。我们必须做重载决议上int.TryParse,以确定哪些的TryParse超载是预期的一个(或,如果没有他们的工作,是什么错误。)重载总是试图从的参数的推断。在这种情况下,虽然,它恰恰是我们试图推断出参数的类型。



我们可以想出一个新的重载解析算法,说:好,如果只有一个方法组中的方法,然后选择一个,即使我们不知道的论据是什么,但似乎无力。这似乎是一个坏主意,那只有一个方法,他们因为然后惩罚你添加新的重载特殊情况的方法组;它可以一下子被打破变化。



你可以从评论该文章看,我们得到了很多的就可以了良好的反馈。最好的反馈意见得到基本上是好了,假设类型推断具有的的制定出类型所有的说法,这是的返回类型的,我们正在试图推断;在这种情况下,你可以做重载决议。这种分析是正确的,改变这种效果走进C#4.我谈过多一点的位置:



http://blogs.msdn.com/b/ericlippert/archive/2008/05 /28/method-type-in​​ference-changes-part-zero.aspx




我是否理解正确的扩展方法做不会被发现的委托类型,因为我想他们不是真正的那种类型的(不过是一个方法),只有正好匹配代表签名?




您术语有点过,但你的想法是正确的。我们没有发现扩展方法时,接收器是的方法组的。更一般地,我们没有发现扩展方法时,接收机的东西,缺乏其自身的类型,而是发生在根据它的上下文类型:方法组,lambda表达式,匿名的方法和null文本都具有这种特性。这将是非常奇怪的说 null.Whatever()并调用扩展方法的字符串,甚至是怪异,(X => X + 1).Whatever()并具有呼吁的扩展方法Func键< INT,INT方式>



描述该行为规范的线路是:




这是隐式标识,引用或装箱转换[必须存在]从[接收者表达]在第一个参数[...]


的方法组

转换是类型没有身份,引用或装箱转换;它们是方法组转化




难道是infeasable使方案1的工作(不是这一个具体的过程,但在一般) ?我从一个语言/编译器的角度进行猜测,它实际上是有用的,还是我只是(试图)在这里疯狂地滥用的东西呢?




这不是的不可行的。我们已经有了一个相当聪明的团队在这里和那里是没有的理论的原因,它是不可能这样做的。它只是似乎没有我们像一个功能,增加了更多的价值比的额外的复杂性成本的语言。



有一些时候将是有益的。例如,我想能够做到这一点;假设我有一个静态Func键< A,R> memoize的< A,R>(本功能使< A,R&F)的温度{...}

 变种FIB =(N =将N 2 1:FIB(N-1)+ FIB(N-2))。memoize的(); 



而不是你今天写的,这是什么:

  Func键< INT,INT> FIB = NULL; 
FIB = N =将N 2 1:FIB(N-1)+ FIB(N-2);
FIB = fib.Memoize();



但坦白地说,额外的复杂性所提出的功能,增加了语言不受本小利支付在作出上述更简洁的代码。


Ladies and Gents,

I recently tried this experiment:

static class TryParseExtensions
{
    public delegate bool TryParseMethod<T>(string s, out T maybeValue);
    public static T? OrNull<T>(this TryParseMethod<T> tryParser, string s) where T:struct 
    {
        T result;
        return tryParser(s, out result) ? (T?)result : null;
    }
}

// compiler error "'int.TryParse(string, out int)' is a 'method', which is not valid in the given context"
var result = int.TryParse.OrNull("1");  // int.TryParse.OrNull<int>("1"); doesnt work either

// compiler error: type cannot be infered....why?
var result2 = TryParseExtensions.OrNull(int.TryParse, "2"); 

// works as expected
var result3 = TryParseExtensions.OrNull<int>(int.TryParse, "3");
      var result4 = ((TryParseExtensions.TryParseMethod<int>)int.TryParse).OrNull("4");

I am wondering two things:

  • Why can the compiler not infer the "int" type parameter?

  • Do I understand correctly that extensions methods do not get discovered on Delegate types, as I guess they arent really of that type (but are a "Method") that only happen to match the delegates signature? As such a cast solves this. Would it be infeasable to enable scenario 1 to work (not this one specifically of course, but in general)? I guess from a language/compiler perspective and would it actually be useful, or am I just (attempting to) wildly abusing things here?

Looking forward to some insights. Thnx

解决方案

You have a number of questions here. (In the future I would recommend that when you have multiple questions, split them up into multiple questions rather than one posting with several questions in it; you'll probably get better responses.)

Why can the compiler not infer the "int" type parameter in:

TryParseExtensions.OrNull(int.TryParse, "2");  

Good question. Rather than answer that here, I refer you to my 2007 article which explains why this did not work in C# 3.0:

http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx

Summing up: fundamentally there is a chicken-and-egg problem here. We must do overload resolution on int.TryParse to determine which overload of TryParse is the intended one (or, if none of them work, what the error is.) Overload resolution always tries to infer from arguments. In this case though, it is precisely the type of the argument that we are attempting to infer.

We could come up with a new overload resolution algorithm that says "well, if there's only one method in the method group then pick that one even if we don't know what the arguments are", but that seems weak. It seems like a bad idea to special-case method groups that have only one method in them because that then penalizes you for adding new overloads; it can suddenly be a breaking change.

As you can see from the comments to that article, we got a lot of good feedback on it. The best feedback was got was basically "well, suppose type inference has already worked out the types of all the argument and it is the return type that we are attempting to infer; in that case you could do overload resolution". That analysis is correct, and changes to that effect went into C# 4. I talked about that a bit more here:

http://blogs.msdn.com/b/ericlippert/archive/2008/05/28/method-type-inference-changes-part-zero.aspx

Do I understand correctly that extensions methods do not get discovered on delegate types, as I guess they arent really of that type (but are a "Method") that only happen to match the delegates signature?

Your terminology is a bit off, but your idea is correct. We do not discover extension methods when the "receiver" is a method group. More generally, we do not discover extension methods when the receiver is something that lacks its own type, but rather takes on a type based on its context: method groups, lambdas, anonymous methods and the null literal all have this property. It would be really bizarre to say null.Whatever() and have that call an extension method on String, or even weirder, (x=>x+1).Whatever() and have that call an extension method on Func<int, int>.

The line of the spec which describes this behaviour is :

An implicit identity, reference or boxing conversion [must exist] from [the receiver expression] to the type of the first parameter [...].

Conversions on method groups are not identity, reference or boxing conversions; they are method group conversions.

Would it be infeasable to enable scenario 1 to work (not this one specifically of course, but in general)? I guess from a language/compiler perspective and would it actually be useful, or am I just (attempting to) wildly abusing things here?

It is not infeasible. We've got a pretty smart team here and there's no theoretical reason why it is impossible to do so. It just doesn't seem to us like a feature that adds more value to the language than the cost of the additional complexity.

There are times when it would be useful. For example, I'd like to be able to do this; suppose I have a static Func<A, R> Memoize<A, R>(this Func<A, R> f) {...}:

var fib = (n=>n<2?1:fib(n-1)+fib(n-2)).Memoize();

Instead of what you have to write today, which is:

Func<int, int> fib = null;
fib = n=>n<2?1:fib(n-1)+fib(n-2);
fib = fib.Memoize();

But frankly, the additional complexity the proposed feature adds to the language is not paid for by the small benefit in making the code above less verbose.

这篇关于委托作为第一个参数一个扩展方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆