C# extension method for a method group - c#

I want to implement an extension method for a method. Consider the following code sample (http://dotnetfiddle.net/HztiOo) :
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
A a = new A();
// Noticed that Next() is called twice
Console.WriteLine(a.Next(1));
Console.WriteLine(a.Next(1));
// Works
var withCache = ((Func<int,int>)a.Next).AddCaching();
withCache = new Func<int,int>(a.Next).AddCaching();
withCache = ExtensionMethods.AddCaching<int,int>(a.Next);
// Doesn't work :(
// withCache = a.Next.AddCaching<int,int>();
// Func<int,int> withCache = a.Next.AddCaching();
// Notice that Next() is only called once
Console.WriteLine(withCache(1));
Console.WriteLine(withCache(1));
}
}
public class A
{
public int Next(int n)
{
Console.WriteLine("Called Next("+n+")");
return n + 1;
}
}
public static class ExtensionMethods
{
public static Func<TKey,TVal> AddCaching<TKey,TVal>(this Func<TKey,TVal> fetcher)
{
var cache = new Dictionary<TKey, TVal>();
return k =>
{
if (!cache.ContainsKey(k)) cache[k] = fetcher(k);
return cache[k];
};
}
}
I would like to be able to call the extension method without an explicit cast. In both "doesn't work" examples above, the type system should be able to figure out which overload to use on its own...
Why can't I just use a.Next.AddCaching<int,int>() ?
Note: this is just an example, I am not interested in discussing the best way to add a cache to a method invocation, as there are many other possibilities for this kind of extensions.

According to Eric Lippert blog method group is typeless expression. And you can't do anything, just deal with it.
That's exact reason why you can't implicitly cast it to specific delegate and add extension method to it

You can achieve something stylistically similar to what you are looking for by exposing you method as a Func, as follows (https://dotnetfiddle.net/BTyJdU). Obviously this involves modifying the class, so it can't be achieved with an extension method only.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
A a = new A();
// Noticed that Next() is called twice
Console.WriteLine(a.Next(1));
Console.WriteLine(a.Next(1));
// Works now :)
var withCache = a.Next.AddCaching<int,int>();
withCache = a.Next.AddCaching();
// Notice that Next() is only called once
Console.WriteLine(withCache(1));
Console.WriteLine(withCache(1));
}
}
public class A
{
public Func<int,int> Next;
public A()
{
Next = NextInternal;
}
private int NextInternal(int n)
{
Console.WriteLine("Called Next("+n+")");
return n + 1;
}
}
public static class ExtensionMethods
{
public static Func<TKey,TVal> AddCaching<TKey,TVal>(this Func<TKey,TVal> fetcher)
{
var cache = new Dictionary<TKey, TVal>();
return k =>
{
if (!cache.ContainsKey(k)) cache[k] = fetcher(k);
return cache[k];
};
}
}
I've also put together a fiddle which uses extension methods only. It involves calling an extension on the object rather than the method: https://dotnetfiddle.net/XaLndp
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
A a = new A();
// Noticed that Next() is called twice
Console.WriteLine(a.Next(1));
Console.WriteLine(a.Next(1));
// An alternative, that uses extension methods only
var withCache = a.AddCaching<A,int,int>(x => x.Next);
// Notice that Next() is only called once
Console.WriteLine(withCache(1));
Console.WriteLine(withCache(1));
}
}
public class A
{
public int Next(int n)
{
Console.WriteLine("Called Next("+n+")");
return n + 1;
}
}
public static class ExtensionMethods
{
public static Func<TKey,TVal> AddCaching<T,TKey,TVal>(this T wrapped, Func<T,Func<TKey,TVal>> fetcher)
{
var cache = new Dictionary<TKey, TVal>();
return k =>
{
if (!cache.ContainsKey(k)) cache[k] = fetcher(wrapped)(k);
return cache[k];
};
}
}

You are able to write extension methods for delegates. In your example:
Why can't I just use a.Next.AddCaching() ?
In that question, a.Next isn't a type. Extension methods only work for types. Think about it. In your AddCaching extension method, what would you write after this? You need a type. In this case, you used the delegate Func<TKey,TVal>. That means it'll extend that delegate. For you example to compile, you need to write:
((Func<int,int>)a.Next).AddCaching<int,int>()
This will compile properly. Additionally, since you are defining the generic types in the delegate, you can actually call it like this:
((Func<int,int>)a.Next).AddCaching()
It'll know it is using <int,int> from the delegate.
So, you were close, you just needed to cast a.Next to a type, the delegate Func<int,int> for it to compile. It is the same rules that apply to extending any other type in the language.

Related

Pass instance method as a parameter without an instance

I was wondering if, in C#, one could pass an instance method as a delegate without an instance. For reference, this is possible in Java by doing example(InstanceClass::InstanceMethod). The compiler then turns this into the equivalent of a Func<InstanceClass, ReturnType> which calls InstanceMethod() on the provided InstanceClass like so: item=>item.InstanceMethod(). Is this possible in C# and if it is, how would one do it?
Edit: To clarify, I am asking how I can pass the method in C# without using a lambda expression. The Lambda expression given is an example of what the compiler would turn the call into. Just passing the method instead of using a Lambda expression would be useful if the method had many arguments
Edit 2: Here is an example to illustrate my question. Java:
class Instance{
public void InstanceMethod(){System.out.println("Hello World");}
public static void Example(){
ArrayList<Instance> list = new ArrayList<>(5);
list.add(new Instance());
list.forEach(Instance::InstanceMethod)
}
}
Output: Hello World
C#:
public class Instance{
public void InstanceMethod(){Console.WriteLine("Hello World");}
public static void ForEach<T>(this IEnumerable<T> input, Action<T> action){
foreach(T item in input){
action(item);
}
}
public static void Example(){
List<Instance> list = new ArrayList<>(5);
list.Add(new Instance());
list.ForEach(Instance.InstanceMethod);//error need instance to call method
}
Even in Java you are still dealing with an instance, but Java's syntactic sugar hides that.
There is no equivalent for your case. You have to do
public static void Example()
{
var list = new List<Instance>(5);
list.Add(new Instance());
list.ForEach(x => x.InstanceMethod());
}
or addstatic toInstanceMethod (since that method has no state):
public static void InstanceMethod()
{
Console.WriteLine("Hello World");
}
public static void Example()
{
var list = new List<Instance>(5);
list.Add(new Instance());
list.ForEach(x => InstanceMethod());
}
If your InstanceMethod accepted an Instance as a parameter and Example wasn't static, there is some C# syntactic sugar called a method group that would work:
public void InstanceMethod(Instance x)
{
Console.WriteLine("Hello World");
}
public void Example()
{
var list = new List<Instance>(5);
list.Add(new Instance());
list.ForEach(InstanceMethod);
}
Of all of the above, the first one is idiomatic C# and the one I would pick. It's probably the most readable and expected for C# programmers to read.

Adding a shim to a static method

I've got some legacy code to add unit testing to. I can add shims where necessary to classes that need instanciating, but some of the code uses static classes. I can't add a shim properly.
for example (simplified for clarity):
public static class DBHelper
{
public static ObservableCollection<Run> GetRuns()
{
ObservableCollection<Run> retval = new ObservableCollection<Run>();
using (AriaEntities DBC = new AriaEntities())
{
var res = DBC.Runs.OrderByDescending(x => x.Run_Number).Take(100).ToList();
retval = new ObservableCollection<Run>(res);
}
return retval;
}
}
I want to shim this method. if it was non static, I'd use:
using (ShimsContext.Create())
{
ShimDBHelper.AllInstances.GetRuns = (i) => { return FakeRunList(); };
...
}
But with a static I get "'DBHelper': static types cannot be used as parameters". If I remove the parameter, I get told that the delegate doesn't take 0 arguments.
Whats the syntax for a static class, if there is one?

Restrict an IList<T> extension method to exclude Arrays

Supposing I create an extension method for IList but this extension is part of a library potentially used across many projects. I do not have the control on how it is called.
Is there a way to prevent an Array to call an IList<T> extension method at compile time? This to avoid any misuse, the caller cannot guess the exact implementation, if the .Add() method would be called or only the indexer for example.
I could not find a possible solution with generic constraint type.
So far the only possibility left would be to restrict the extension method to List<T> directly.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var array = new[]{"Hello"};
array.DummyInsert("World"); // this will crash at run time
}
}
public static class DummyExtension
{
public static T DummyInsert<T>(this IList<T> list, T insertValue)
{
list.Add(insertValue);
return insertValue;
}
}
You can add your extension method to List<T> not on IList<T>
I Agree with Ed Plunkett, use a ReadOnlyCollection<T>. But you can do it like this. It's your foot, you can shoot it if you want.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var array = new[]{"Hello"};
var world = array.Insert("World"); // this will crash at run time
Console.WriteLine(array.Length);
}
}
public static class DummyExtension
{
public static T Insert<T>(this IList<T> list, T insertValue)
{
Console.WriteLine("WrongInsert");
list.Add(insertValue);
return insertValue;
}
[Obsolete("If want a compile time exception you can do this too.", true)]
public static T Insert<T>(this T[] list, T insertValue)
{
Console.WriteLine("RightInsert");
return insertValue;
}
}
This prints
RightInsert
1
https://dotnetfiddle.net/i6p1Z5
EDIT:
It was pointed out in the comments below that this won't work if your array has been cast to an IList<T> either explicitly or implicitly. There is nothing wrong with using List<T> here instead of IList<T> unless you are trying to actually extend the IList<T>. In that case extend it in a way that makes sense for all IList<T>. I just wanted to show that yes, what you ask can be done. With great power comes great responsibility.
The run-time issue is because of the fact that the Array is of fixed length hence when you try to insert an element into it you end up with an exception. Instead you can have your own extension method for case Array and handle the insertion accordingly.
public class Program
{
public static void Main()
{
var array = new[] { "Hello" };
array = array.Insert("World");
}
}
public static class DummyExtension
{
public static T Insert<T>(this IList<T> list, T insertValue)
{
list.Add(insertValue);
return insertValue;
}
public static T[] Insert<T>(this T[] list, T insertValue)
{
var destArray = new T[list.Length + 1];
Array.Copy(list, destArray, list.Length);
destArray[destArray.Length - 1] = insertValue;
return destArray;
}
}
Well I agree it may be a crude way, but it will work for your case.

Does C# support a __call__ method?

Python has this magic __call__ method that gets called when the object is called like a function. Does C# support something similar?
Specifically, I was hoping for a way to use delegates and objects interchangeably. Trying to design an API where a user can pass in a list of functions, but sometimes those functions need some initial params, in which case they'd use one of those callable objects instead.
Sure, if you inherit from DynamicObject. I think you're after TryInvoke which executes on obj(...), but there are several other method you can override to handle casting, index access (obj[idx]), method invocations, property invocations, etc.
using System;
using System.Diagnostics;
using System.Dynamic;
using System.Linq;
using System.Text;
namespace ConsoleApplication {
public static class ConsoleApp {
public static void Main() {
dynamic x = new MyDynamicObject();
var result = x("awe", "some");
Debug.Assert(result == "awesome");
}
}
public class MyDynamicObject : DynamicObject {
public override Boolean TryInvoke(InvokeBinder binder, Object[] args, out Object result) {
result = args.Aggregate(new StringBuilder(), (builder, item) => builder.Append(item), builder => builder.ToString());
return true;
}
}
}
I bow to Simon Svensson - who shows a way to do it if you inherit from DynamicObject - for a more strait forward non dynamic point of view:
Sorry but no - but there are types of objects that can be called - delegates for instance.
Func<int, int> myDelagate = x=>x*2;
int four = myDelagate(2)
There is a default property though - that has to have at least one parameter and its access looks like an array access:
class Test1
{
public int this[int i, int j]
{
get { return i * j; }
}
}
Calling
Test1 test1 = new Test1();
int six = test1[2, 3];
Then you can do some really silly stuff with delegates like this:
class Test2 // I am not saying that this is a good idea.
{
private int MyFunc(int z, int i)
{
return z * i;
}
public Func<int, int> this[int i] { get { return x => MyFunc(x, i); } }
}
Then calling it looks weird like this:
Test2 test = new Test2();
test[2](2); // this is quite silly - don't use this.....
This would be akin to overloading the function call operator (as is possible in C++). Unfortunately, this is not something which is supported in C#. The only objects that can be called like methods are instances of delegates.

Why can't I implicitly cast a Delegate with Extension methods?

I'm trying to figure out a way to automatically cast something to an Action or Func and the best I can come up with is something like this:
[TestFixture]
public class ExecutionTest
{
public void BadMethod()
{
throw new Exception("Something bad happened");
}
[Test]
public void TestBadMethod()
{
// Want this, but it won't work!!
// BadMethod.Execute().IgnoreExceptions();
// Ick
((Action)BadMethod).Exec().IgnoreExceptions();
// Still ick
((Action)BadMethod).IgnoreExceptions();
// Do not want
ExtensionMethods.Exec(BadMethod).IgnoreExceptions();
// Better but still meh
this.Exec(BadMethod).IgnoreExceptions();
}
}
public static class ExtensionMethods
{
public static Action Exec(this Action action)
{ return action; }
public static Action Exec(this object obj, Action action)
{ return action; }
public static void IgnoreExceptions(this Action action)
{
try { action(); }
catch {}
}
}
There has to a better/easier way to do this, any thoughts?
In C#, when you use the method name without parenthesis, it's called a method group and it has no representation other than at compile time. A method group can represent more than one method (because of overloads and overrides), therefore to implicitly identify which method is needed, a target delegate type must be provided.
In your case, you are wondering why the extension method parameter type won't trigger the resolution of the function. Simply put, extension are evaluated after the type is known, that is, the this parameter can't be used as an implicit conversion target.
Example of why it would break:
class Test
{
void M (void) // Fits Action delegate
{
}
int M (int) // Fits Func<int,int> delegate
{
return 5;
}
void Test()
{
M.Exec(); // UHOH!!! Which Exec to resolve to ???
}
}
public static class Extensions
{
public static void Exec(this Action action) { }
public static void Exec(this Func<int, int> func) { }
}
As you can see, there is a conflict, but as a matter of fact, the conflict never happens because C# won't even try to find a matching extension with a method group.
Note how this won't work either:
class A
{
public static implicit operator int (A a)
{
return 5;
}
void F()
{
A a = new A();
a.Blah(); // Error! It won't implicitly try C.Blah()
}
}
public static class C
{
public static void Blah (int i)
{
}
}
C# won't match A to C.Blah(int) because it would require an implicit conversion.
As Coincoin says, it's not gonna work well in C# because of the overzealous love for method overloading. The only workaround I've seen people use is to create Action and Func methods:
public Action Action(Action f) { return f; }
public Action<A> Action<A>(Action<A> f) { return f; }
...
public Func<A,B,C,D,E> Func(Func<A,B,C,D,E> f) { return f; }
You could even call them all "F" to get some sort of short syntax:
F(BadMethod).NoExceptions();
You might decide to not define these methods in your class, and put them in a Funcs utility or something. Alias it with F and it doesn't end up too bad:
F.F(BadMethod).NoException();
But overall it still sucks :(.
F# lets you do this kind of thing very naturally by providing a much better type inference system.

Categories

Resources