Reputation: 1455
I want to create a custom class that wraps a delegate and have an implicit operator to cast a method to it so I can create an invocation list, but c# doesn't allow direct cast, only 2 step cast. How can you do that?
public class Test
{
public class CustomFunc<T> {
private Func<T> Func { get; set; }
public CustomFunc(Func<T> func)
{
Func = func;
}
public void DoSomething() {
}
public void Invoke()
{
//do something else
Func.Invoke();
}
public static implicit operator CustomFunc<T>(Func<T> func) { return new CustomFunc<T>(func); }
}
public void Main() {
AddTestMethod(TestMethod);//this gives "Argument 1: cannot convert from 'method group' to 'Test.CustomFunc<bool>'" compilation error
AddTestMethodThatWorks(TestMethod);//<- this works
}
public void AddTestMethod(CustomFunc<bool> func) {
func.DoSomething();
//add method to an invocation list
}
public void AddTestMethodThatWorks(Func<bool> func)
=> AddTestMethod(func);
public bool TestMethod()
{
return true;
}
}
Upvotes: 0
Views: 1159
Reputation: 660189
The question (as originally stated, before recent edits) is somewhat vague. Let's start by formulating a crisp question:
Is there a way in C# to convert directly, without a cast, via a user-defined implicit conversion, from a method group to an arbitrary type?
No.
Well that was an easy answer to write, but possibly unsatisfying. Let's ask another crisp question:
Where are the rules for user-defined implicit conversions described?
Ostensibly here:
A careful reading of that section immediately shows why we have a problem:
A user-defined implicit conversion from type S to type T is processed as follows:
Method groups do not have a type, and so any rule that begins "conversion from type" is likely to not apply to method groups. However, that's not the real problem here. The real problem lies in the rules for determining the semantics of user-defined implicit conversions.
Can you briefly summarize the rules for implicit user-defined conversions?
Briefly, the rule is that the "source" expressions may have a "standard" conversion -- that is, not a user-defined conversion -- put "on top" of it before the user-defined conversion. For example, if we have a user defined conversion from double
to Square
, and we are converting an int
to Square?
, then the int
is allowed to first be converted to double
via a "standard" conversion, and then to Square
, and then to Square?
. You can end up chaining several "standard" conversions if you are clever, but you never end up chaining two user-defined conversions.
Unfortunately for you, method group conversions are not considered "standard implicit conversions".
What are the standard implicit conversions?
Identity, numeric, reference, boxing, nullable, and generic type parameter conversions are standard conversions. Conversions involving method groups, lambdas and anonymous functions are not standard conversions, and obviously user-defined conversions are not standard conversions.
What were the design considerations made in favour of restricting method group conversions from the standard conversions?
We considered method group conversions to be potentially confusing when used in user-defined conversions because (1) they may involve overload resolution (2) they may involve various kinds of inference, and (3) we did not consider scenarios such as yours to be likely in line-of-business scenarios. Basically, they would complicate a feature that is already too complicated and poorly understood, for very little gain. We had other things to spend effort on.
If you have a business scenario that would strongly motivate re-examining this design decision, consider raising an issue on the github site and start a new discussion. Things may have changed since 2001 when the decision was made to not allow method group conversions as a standard conversion.
If you're reading this answer carefully you'll have noted that I said "ostensibly" above.
Why did you do that, Eric?
First, because the spec was supposed to be rewritten to include rules for "conversion from expression" instead of "conversion from type", but apparently this has not happened yet in the online version of the spec. I wrote the notes for that in 2012; I am vexed that it has not made it into the online spec yet.
Second, because the compiler does not exactly implement the rules in the specification.
What are the actual rules for user-defined implicit conversions?
Great question. I wrote extensive notes on that subject, here:
If you wish to understand how exactly user-defined implicit conversion operators really work in C#, you'll have to read all those comments. I know, they are very long. You will find that they take you less time to read than they took me to write.
If none of the above answers your question, please ask a less vague question; I am happy to answer crisp questions about this feature area, which is complicated and poorly understood.
Upvotes: 10