Passing method as parameter to function - c#

Is there a way of passing in a method to a function as a parameter and then calling it via list.Sort()? I've tried this:
public static string BuildHumanSitemap(Func<TreeNode, TreeNode, int> sortMethod, params string[] classNames)
{
//calling list sort on method passed as parameter
nodes.sort(sortMethod);
}
Where the functions i want to pass in all take the same params e.g.
private static int SortByDateCreated(TreeNode x, TreeNode y)
{
DateTime xT = (DateTime)x["DocumentCreatedWhen"];
DateTime yT = (DateTime)y["DocumentCreatedWhen"];
return xT.CompareTo(yT);
}
I've also tried using an Action delegate type but the sort method complains when i pass it as a parameter. Can anyone offer a suggestion on how to do this?
Thankyou

Create new Comparison delegate and pass it to Sort method:
nodes.Sort(new Comparison<TreeNode>(sortMethod));

Maybe instead of taking in a Func<,,> delegate, you should consume a Comparison<> delegate. Because that's what List<> wants (for historical reasons; the List<>.Sort method was written for .NET 2.0, before the Func delegates were introduced).
Therefore:
public static string BuildHumanSitemap(Comparison<TreeNode> sortMethod, params string[] classNames)
{
//calling list sort on method passed as parameter
nodes.Sort(sortMethod);
}
Then call your method very simply like this:
BuildHumanSitemap(SortByDateCreated);
where SortByDateCreated is the "method group" from your question.
There's no need for first creating a delegate instance of type Func<TreeNode, TreeNode, int> and then create another delegate instance (of type Comparison<TreeNode>) which references the first one.
Of course you can also call your BuildHumanSitemap method with a lambda arrow as the first argument.

It works this way:
TreeView.TreeViewNodeSorter = new CustomNodeSorter();
private class CustomNodeSorter : IComparer
{
public int Compare(object x, object y)
{
DateTime xT = (DateTime)x["DocumentCreatedWhen"];
DateTime yT = (DateTime)y["DocumentCreatedWhen"];
return xT.CompareTo(yT);
}
}

Solution with IComparer<T>.
Comparer
public class MyTreeNodeComparer : IComparer<TreeNode>
{
public int Compare(TreeNode x, TreeNode y)
{
DateTime xT = (DateTime)x["DocumentCreatedWhen"];
DateTime yT = (DateTime)y["DocumentCreatedWhen"];
return xT.CompareTo(yT);
}
}
Usage
list.Sort(new MyTreeNodeComparer());

Related

Custom Icomparer with argument

How would an IComparer that needs an argument be implemented (might not be relevant but I'm using it on Linq query)?
I suppose it should be called like this:
ListOfObjectsToSort.orderBy(x => x, myCustomComparer(argument));
And this is what i found on how to implement the IComparer but i can't figure out how to change it to pass the argument here:
public class MyComparer : IComparer<object>
{
public int Compare(object x, object y)
{
// code will then return 1,-1 or 0
You can't add an argument to the Compare method or you violate the interface contract. Add a property to the class that can be used in the method:
public class MyComparer : IComparer<object>
{
public int MyArgument {get; set;}
public int Compare(object x, object y)
{
// code will then return 1,-1 or 0
// use MyArgument within the method
}
You can set it in the constructor:
public MyComparer(int argument)
{
MyArgument = argument;
}
Then your syntax would be:
var myCustomComparer = new MyComparer(argument);
ListOfObjectsToSort.orderBy(x => x, myCustomComparer);
or just
ListOfObjectsToSort.orderBy(x => x, new MyComparer(argument));
the problem is that this cannot be done exactly as you're asking.
The reason for this is that you're trying to change the signature of the Compare method, which would result in outside libraries (like Linq!) being unable to call the method, because the arguments they pass are no longer the arguments needed. Thus, the compiler simply does not allow this.
However, there is a way around this, for this particular case, in that since IComparers are used as objects, you could create a class which implements IComparer and takes a custom object in the constructor, saving it to a field and using that for comparison calculations. Thus, you end up with
var comp = new CustomComparer(argument);
ListOfObjectsToSort.OrderBy(x => x, comp);

How could I achieve JQuery style method calls on IEnumerables in C#?

In JQuery you can write $('.my-class').hide() and it will call hide() on all the results. There's no for loop, no iterating, no LINQ extensions and lambdas etc. and it makes dealing with lists super fun. I want to be able to have this functionality on IEnumerables in C#. I think Matlab has a similarly concise syntax when operating on arrays/matrices.
Long story short, I want the following code (or similar) to work:
class Program
{
static List<MyClass> MyList = new List<MyClass>();
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
MyList.Add(new MyClass());
MyList.MyMethod();
// should be exactly equivalent to:
MyList.Select(n => n.MyMethod());
}
}
class MyClass
{
public int MyMethod() { return 123; }
}
I'm aware this is possible on a case-by-case basis using extension methods:
public static IEnumerable<int> MyMethod(this IEnumerable<MyClass> lst)
{
return lst.Select(n => n.MyMethod());
}
But we'd have to create one extension method for every single method on every single type that you wanted this behaviour on.
Ideally this would be possible for all types and all methods and still be type-safe at compile time. I suspect I'm asking too much from the C# language here, but how would we do this or something similar in a as-generic-as-possible way?
Possible solutions:
Auto-generate extension methods for particular types. If we only intend to use this notation for a few types, we could just generate the extension methods once automatically. This would achieve the exact syntax and full type safety but generating code would be a pain.
A single extension method that returns a dynamic object built using reflection on the supplied type. The idea is that we'd use reflection to iterate through the type's methods and build up a dynamic object that would have all the methods like .MyMethod() that would behind the scenes call Select(...) on the IEnumerable. The syntax would end up being something like MyList.Selector().MyMethod(). But now we've lost the syntax and type safety. Clever, maybe. Useful, probably not.
Intercepting method calls? Is it possible to decide how to react to a method call at runtime? I don't know. Again you'd lose type safety.
The most simple solution is using dynamic objects. If you are willing to throw away type safety, you can make a IEnumerable type that behaves statically when needed and dynamically otherwise, here's a sample prototype:
public class DynamicIEnumerable<T> : DynamicObject, IEnumerable<T>
{
public IEnumerable<T> _enumerable;
public DynamicIEnumerable(IEnumerable<T> enumerable)
{
this._enumerable = enumerable;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = new DynamicIEnumerable<T>(_enumerable.Select(x => (T)typeof(T).InvokeMember(binder.Name, BindingFlags.InvokeMethod, null, x, null)));
return true;
}
public IEnumerator<T> GetEnumerator()
{
return _enumerable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _enumerable.GetEnumerator();
}
}
In TryInvokeMember, the invoked member on IENumerable is applied on all items using reflection. The only constraints on this approach is that you have to return this in invoked method. Here's a sample of how to use this approach:
public class SomeClass
{
public int Value {get;set;}
public SomeClass(int value)
{
this.Value = x;
}
public SomeClass Plus10()
{
Value += 10;
return this;
}
}
static void Main()
{
dynamic d = new DynamicIEnumerable<X>(Enumerable.Range(0, 10).Select(x => new SomeClass(x)));
foreach (var res in d.Plus10().Plus10())
Console.WriteLine(res.Value);
}
how would we do this or something similar in a as-generic-as-possible way?
This isn't a pretty solution but it does work:
public class MyClass
{
public void MyMethod()
{
}
public void MyMethod2()
{
}
}
Extension Method:
public static class WeirdExtensions
{
public static IEnumerable<T> CallOnAll<T>(this IEnumerable<T> instance ,
Action<T> call)
{
foreach(var item in instance)
{
call(item);
}
return instance;
}
}
Usage (chaining/fluent):
var blah = new List<MyClass>();
blah.CallOnAll(b => b.MyMethod())
.CallOnAll(b => b.MyMethod2());
Notes
This isn't quite possible due to a the underlying assumption that you'd have to every single method on every single type. In jQuery/Html there is only one underlying type of an Html Element. All elements are exposed to the same methods (whether or not the type supports it). In jQuery, you can call $('head').hide() but it won't do anything visually, but because it is an element, it will be inline styled. If you need a new method, you do have a build one, but for only one type because there is only one type.
In contrast with C# you build your types (many many types) and they all have different methods (sure there could be overlap).

Using Comparison<T>() comparison with the three arguments overload

I have a List<Points>() and I want to sort it with a custom comparer function.
I made:
public int MyCompare(Point p1, Point p2)
{
...
}
// In my main
// ...
points_.Sort(MyCompare);
// ...
I works, all right.
Now I want to sort everything but the first element, so I thought to do:
points_.Sort(1, points_.Count()-1, MyCompare);
But with this overload he wants as argument an IComparer.
How can I solve this?
Note that Point is not a custom class, it is from Xna framework. I don't want to implement a custom class with : IComparer
If you do not want to implement IComparer, you could create one from a delegate using the Comparer<T>.Create static method, like this:
points_.Sort(1, points_.Count()-1, Comparer.Create(MyCompare));
or even
points_.Sort(1, points_.Count()-1, Comparer.Create((a, b) => {
... // comparison logic goes here
}));
As pointed out by #dasblinkenlight with .NET 4.5+ there's an ad-hoc method to convert a Comparison<T> delegate to an IComparer<T>.
But if you're stuck with a lower version, you can use this class to convert a Comparison<T> delegate to IComparer<T>:
public class DelegateComparer<T> : IComparer<T>
{
private readonly Comparison<T> compDelegate;
public DelegateComparer(Comparison<T> compDelegate)
{
if (compDelegate == null)
throw new ArgumentNullException("compDelegate");
this.compDelegate = compDelegate;
}
public int Compare(T x, T y)
{
return compDelegate(x, y);
}
}
Usage example:
points_.Sort(1, points_.Count()-1, new DelegateComparer<Point>(MyCompare));

Sort a List<T> by using a passed in function

I have a function I'd like to write where return a sorted list. I want to pass in a custom comparison for the objects. The examples below are rather oversimplified, but if I can get past this, I should be set.
I've tried declaring a delegate of the right type (I think):
public delegate int ObjectSorter(MyObject x, MyObject y);
Calling it with the right syntax:
GetList(delegate(MyObject a, MyObject b) { return a.CompareTo(b); });
But when I pass that to the list, I get that there are argument problems:
public List<MyObject> GetList(ObjectSorter os)
{
List<MyObject> objectList = FillTheList();
objectList.Sort(os); // Invalid
return ObjectList;
}
So trying a different approach:
GetList((x, y) => { return x.CompareTo(y); });
public List<MyObject> GetList(Func<MyObject, MyObject, int> sorter)
{
List<MyObject> objectList = FillTheList();
objectList.Sort(sorter); // Invalid also
// This syntax DOES work, but too specific. And why does it work?
nl.Sort((x, y) => x.CompareTo(y));
return ObjectList;
}
Doesn't work either.
I'm trying to make this as easy as possible for the caller to get a custom comparison into the function, and for the function to know as little as possible about the workings of the sort itself. I'd rather not have the caller go through all of the trouble of creating an class derived from IComparer and passing that in.
Should be:
objectList.Sort(new Comparison<MyObject>(sorter));
Or just change your method signature to:
public List<MyObject> GetList(Comparison<MyObject> sorter)
Comparison<MyObject> is equivalent to your Func<MyObject, MyObject, int> sorter.
nl.Sort((x, y) => x.CompareTo(y)); works because the compiler automatically turns (x, y) => x.CompareTo(y) into a Comparison<MyObject> delegate. When you have the code (x, y) => x.CompareTo(y), the compiler uses the context to determine its type.
Once it's stored as a specific delegate type (e.g. Func<MyObject, MyObject, int> or Comparison<MyObject>), that is its type, and it will not implicitly be converted to another. However, it can be explicitly converted to another type if it is compatible, as in new Comparison<MyObject>(sorter).
You can pass in a function using Func for example:
private void Foo(Func<MyObject, MyObject, int> sortMethod)
{
list.Sort(new Comparison<MyObject>(sortMethod));
}
Example sort method:
public static int SortBytName(MyObject x, MyObject y)
{
return x.Name.CompareTo(y.Name);
}

Passing a Function (with parameters) as a parameter?

I want to create a generic to which I can pass a function as a parameter, however this function may include parameters itself so...
int foo = GetCachedValue("LastFoo", methodToGetFoo)
Such that:
protected int methodToGetFoo(DateTime today)
{ return 2; // example only }
Essentially I want to have a method that will check the cache for a value, otherwise will generate the value based on the passed in method.
Thoughts?
It sounds like you want a Func<T>:
T GetCachedValue<T>(string key, Func<T> method) {
T value;
if(!cache.TryGetValue(key, out value)) {
value = method();
cache[key] = value;
}
return value;
}
The caller can then wrap this in many ways; for simple functions:
int i = GetCachedValue("Foo", GetNextValue);
...
int GetNextValue() {...}
or where arguments are involved, a closure:
var bar = ...
int i = GetCachedValue("Foo", () => GetNextValue(bar));
Use System.Action and a lambda expression (anonymous method). For example:
public void myMethod(int integer) {
// Do something
}
public void passFunction(System.Action methodWithParameters) {
// Invoke
methodWithParameters();
}
// ...
// Pass anonymous method using lambda expression
passFunction(() => myMethod(1234));
You can create your own delegate, but in C# 3.0 you may find it more convenient to use the built-in Func<T> delegate family to solve this problem. Example:
public int GetCachedValue(string p1, int p2,
Func<DateTime, int> getCachedValue)
{
// do some stuff in here
// you can call getCachedValue like any normal function from within here
}
This method will take three arguments: a string, an int, and a function that takes a DateTime and returns an int. For example:
int foo = GetCachedValue("blah", 5, methodToGetFoo); // using your method
int bar = GetCachedValue("fuzz", 1, d => d.TotalDays); // using a lambda
Different Func<T, U, V...> etc. types exist in the framework to accommodate methods with different amounts of arguments.
Create a delegate for the method methodToGetFoo
public delegate object GenerateValue(params p);
public event GenerateValue OnGenerateValue;
Define GetCachedValue to use the delegate
int GetCachedValue(string key, GenerateValue functionToCall);
Then in the implementation of OnGenerateValue you can check the param's.
Here is something simple I started that can be taken a bit further (as I did for a commercial project).
In my case this was to cache web service calls, and was used something like:
WebService ws = new WebService();
var result = ws.Call( x => x.Foo("bar", 1)); // x is the ws instance

Categories

Resources