invoking a static method with an instance of the class. why? - c#

This is a small snippet of code that I found.
when we make a call
object.Max(s=>s.Length)
why do we need a static method?
public static TResult Max<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector)
{
return source.Select(selector).Max();
}
please update the question title. I couldnot abstract it well.

That is an extension method (via the this modifier on the first parameter). The obj. is passed in as the first argument instead. So:
obj.Max()
is identical to:
DeclaringType.Max(obj, s=>s.Length)
But note that genuine instance methods always take precedence during static analysis, so if the object had a suitable Max method itself, it would be chosen instead of the extension method.
Extension methods must be static methods on non-nested static classes.

Related

How do I use Func<T, TResult> for a method with in parameters?

I'm trying to declare a Func<T, TResult> for a static method on a struct that has in parameters.
The signature of my method is something like this:
public static MyStruct MyMethod(in MyStruct input);
I tried to declare the Func this way:
new Func<MyStruct, MyStruct>(MyStruct.MyMethod);
But this causes an error:
"No overload for 'MyMethod' matches delegate Func<MyStruct, MyStruct>."
I did some googling, and found the following information in the Microsoft docs:
The encapsulated method must correspond to the method signature that is defined by this delegate. This means that the encapsulated method must have one parameter that is passed to it by value, and that it must return a value.
(https://learn.microsoft.com/en-us/dotnet/api/system.func-2?view=netcore-3.1)
From my code, I can see this to be true as I have some Funcs working properly for methods on this struct with in parameters, and they have another argument passed by value.
So my question has two parts, firstly why does at least one argument to a Func<> have to be passed by value? And secondly, how can I achieve getting a Func<> which will encapsulate the static method on my struct?

Why doesn't Compile() run every time the method is called?

Here is a code piece from MiscUtil library (by Jon Skeet & Marc Gravell):
static T Add<T>(T a, T b) {
//TODO: re-use delegate!
// declare the parameters
ParameterExpression paramA = Expression.Parameter(typeof(T), "a"),
paramB = Expression.Parameter(typeof(T), "b");
// add the parameters together
BinaryExpression body = Expression.Add(paramA, paramB);
// compile it
Func<T, T, T> add = Expression.Lambda<Func<T, T, T>>(body, paramA, paramB).Compile();
// call it
return add(a,b);
}
It says below the code that:
Isn't this expensive?
Well, compiling the operators isn't trivial, but the static
constructor ensures that we only do this once for each signature.
What is the reason behind Func<T, T, T> doesn't get compiled every time Add<T>(T a, T b) method is called, but insted only gets compiled once?
There is only one static field per type, it's shared among them. This field is initialized just before first use (see this old documentation from MSDN).
If a static constructor (...) exists in the class, execution of the
static field initializers occurs immediately prior to executing that
static constructor. Otherwise, the static field initializers are
executed at an implementation-dependent time prior to the first use of
a static field of that class.
So when you declare and try to use SomeType<int,int> for the first time, its static field is initialized. When you declare and try to use SomeType<int,int> second time, there is no point in creating this field again. It already exists! It's managed internally by .NET environment. This is how language is designed.
Note that SomeType<int,int> and SomeType<int,long> are different types (different type arguments) and need separate static fields.
Here is a code piece from MiscUtil library (by Jon Skeet & Marc Gravell):
No. It says so below the code:
The actual code makes use of static classes and static constructors to cache the operators efficiently, and uses some shared code in ExpressionUtil to simplify the construction of the various Add, Subtract etc operators - but the theory is the same.
That should answer the question of how that code avoids calling Compile() each time: it doesn't, and the page does not claim it does.

What is the bare minimum requirement for a monad to participate in the composition offered by LINQ?

I recall that the C# compiler, when translating from the query expression syntax to calls to the relevant operator methods on the monad, doesn't really care about and doesn't require the monad to have implemented some interfaces.
It doesn't even care of the operator methods are extensions or real instance methods.
But I can't recall the details at all. It seems like there is a bare minimum requirement for the sequence itself, which, in my query below would be the new Foo<string>() expression.
I recall it doesn't necessarily have to adhere to an interface but it either did have to have a method named GetEnumerator or it did have to implement the IEnumerator<T> methods. But I could be wrong since my example query shown below works with or without the presence of a GetEnumerator method in the Foo<T> class.
However, when I introduce a where query expression, that doesn't resolve the type of the receiver.
The Select expression works just fine.
I used to know this at the back of my hand until 18 months ago, which was the time I implemented a trivial LINQ provider. I have since forgotten much of it.
Could you please list the bare minimum requirements for all this to work?
using System;
namespace CompilerDoesNotCareAboutTypeLINQQuerySyntax
{
class Program
{
static void Main(string[] args)
{
// What are the minimum requirements on Foo<T>()?
// How does it resolve this expression new Foo<string>
// such that it knows that Foo<string> has many Bar<string>
// or whatever foo in the query below might resolve to?
var query = from foo in new Foo<string>()
/* where foo. // when I do foo., only the system.object inherited properties of Foo show up */
select foo;
}
}
public class Foo<T>
{
public string Name { get; set; }
public Foo<T> Where<T>(Func<T, bool> predicate)
{
return new Foo<T>();
}
/*IEnumerator<Foo<T>> GetEnumerator()
{
return new List<Foo<T>>().GetEnumerator();
}*/
}
public static class Extensions
{
public static Foo<R> Select<T, R>(this Foo<T> foo, Func<T, R> transformer)
{
return new Foo<R>();
}
}
}
Update
Here's an update of the Where method declaration after implementing the fix that Servy pointed out.
class Foo<T>
{
public Foo<T> Where(Func<T, bool> predicate)
{
return new Foo<T>();
}
}
That fixes the bug due to which foo in the above query expression query resolved to system.object. However, it now resolves to string, which, by inference, is the generic type parameter type of the Where method.
It earlier resolved to object because I had overloaded the generic type parameter T as Servy pointed out, and now it resolves to T, which is the generic type parameter of the declaring type Foo<T>.
The question still remains:
What is the bare minimum requirement on the sequence expression new Foo<string>()? It looks like there is none? Then what is the correlation between the value of the expression that will sit in the place of the sequence and the type of the range variable foo? If I had to make it such that new Foo<T> returned many foos and therefore the foo in the query from foo in new Foo<T>()... resolved to a single Foo<T>, what would need to be done?
The problem here is that you're overloading T in your implementation of Where.
You define T as the generic argument to the type itself, and you also define T as the generic argument to the Where method. Since the method's argument is "closer" it takes precedence. This means that the T in Func<T, bool> is the method arguement's T, *but not the class's T. The class's T is string, but the method's T cannot be inferred to be anything, which is why you're not seeing string members of the parameter.
In this case, it doesn't seem like you need the method to be generic at all, since the type itself is already supplying you with the generic argument. You'd only need that method to be generic if it was an extension method not on the type itself. Just make the method not generic and your code will work just fine.

When creating a fluent api, how do they chained methods get context from previous methods?

I'm looking at this open source project, and the fluent api looks like:
baseEngine.For<Foo1>()
.Setup(f => f.Value)
.MustEqual(1);
Then MustEqual method's parameter list it:
public static M MustEqual<M, T, R>(this IMustPassRule<M, T, R> mpr, R value)
{
return mpr.MustPassRule(new EqualRule<R>(value));
}
for more details: http://rulesengine.codeplex.com/SourceControl/changeset/view/9077#137411
So what I'm trying to get at is, the call to MustEqual is being passed only a single arguement, since it is fluent, is it somehow implicitly picking up other required parameters from the previously chained calls?
The state gets stored in the object itself by those previous methods, if necessary.
You are looking at an Extension Method.
Extension Methods allow static methods to be invoked with instance method syntax. For instance,
something.MustEqual(1);
is equivalent to
RulesHelper.MustEqual(something, 1);
A nice example can be found in LINQ
The IEnumerable<T>.OrderBy returns an IOrderedEnumerable<T>
This second interface keeps track of the order so the IOrderedEnumerable<T>.ThenBy is able to do a sub-sort. To make things smooth the interface derives from IEnumerable<T>

Why Func<T,bool> instead of Predicate<T>?

This is just a curiosity question I was wondering if anyone had a good answer to:
In the .NET Framework Class Library we have for example these two methods:
public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate
)
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
Why do they use Func<TSource, bool> instead of Predicate<TSource>? Seems like the Predicate<TSource> is only used by List<T> and Array<T>, while Func<TSource, bool> is used by pretty much all Queryable and Enumerable methods and extension methods... what's up with that?
While Predicate has been introduced at the same time that List<T> and Array<T>, in .net 2.0, the different Func and Action variants come from .net 3.5.
So those Func predicates are used mainly for consistency in the LINQ operators. As of .net 3.5, about using Func<T> and Action<T> the guideline states:
Do use the new LINQ types Func<> and
Expression<> instead of custom
delegates and predicates
I've wondered this before. I like the Predicate<T> delegate - it's nice and descriptive. However, you need to consider the overloads of Where:
Where<T>(IEnumerable<T>, Func<T, bool>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)
That allows you to filter based on the index of the entry as well. That's nice and consistent, whereas:
Where<T>(IEnumerable<T>, Predicate<T>)
Where<T>(IEnumerable<T>, Func<T, int, bool>)
wouldn't be.
Surely the actual reason for using Func instead of a specific delegate is that C# treats separately declared delegates as totally different types.
Even though Func<int, bool> and Predicate<int> both have identical argument and return types, they are not assignment-compatible. So if every library declared its own delegate type for each delegate pattern, those libraries would not be able to interoperate unless the user inserts "bridging" delegates to perform conversions.
// declare two delegate types, completely identical but different names:
public delegate void ExceptionHandler1(Exception x);
public delegate void ExceptionHandler2(Exception x);
// a method that is compatible with either of them:
public static void MyExceptionHandler(Exception x)
{
Console.WriteLine(x.Message);
}
static void Main(string[] args)
{
// can assign any method having the right pattern
ExceptionHandler1 x1 = MyExceptionHandler;
// and yet cannot assign a delegate with identical declaration!
ExceptionHandler2 x2 = x1; // error at compile time
}
By encouraging everyone to use Func, Microsoft is hoping that this will alleviate the problem of incompatible delegate types. Everyone's delegates will play nicely together, because they will just be matched up based on their parameter/return types.
It doesn't solve all problems, because Func (and Action) can't have out or ref parameters, but those are less commonly used.
Update: in the comments Svish says:
Still, switching a parameter type from
Func to Predicate and
back, doesn't seem to make any
difference? At least it still compiles
without any problems.
Yes, as long as your program only assigns methods to delegates, as in the first line of my Main function. The compiler silently generates code to new a delegate object that forwards on to the method. So in my Main function, I could change x1 to be of type ExceptionHandler2 without causing a problem.
However, on the second line I try to assign the first delegate to another delegate. Even thought that 2nd delegate type has exactly the same parameter and return types, the compiler gives error CS0029: Cannot implicitly convert type 'ExceptionHandler1' to 'ExceptionHandler2'.
Maybe this will make it clearer:
public static bool IsNegative(int x)
{
return x < 0;
}
static void Main(string[] args)
{
Predicate<int> p = IsNegative;
Func<int, bool> f = IsNegative;
p = f; // Not allowed
}
My method IsNegative is a perfectly good thing to assign to the p and f variables, as long as I do so directly. But then I can't assign one of those variables to the other.
The advice (in 3.5 and above) is to use the Action<...> and Func<...> - for the "why?" - one advantage is that "Predicate<T>" is only meaningful if you know what "predicate" means - otherwise you need to look at object-browser (etc) to find the signatute.
Conversely Func<T,bool> follows a standard pattern; I can immediately tell that this is a function that takes a T and returns a bool - don't need to understand any terminology - just apply my truth test.
For "predicate" this might have been OK, but I appreciate the attempt to standardise. It also allows a lot of parity with the related methods in that area.

Categories