I have this delegate declaration:
public delegate IEnumerable<T> SearchInputTextStrategy<T, U>(string param);
Lets assume I did create here the new SearchInputTextStrategy delegate and name it MyDelegate.
this is my method declaration:
public void BindElements<T, TDisplayProperty,TSortProperty>
(
IEnumerable<T> dataObjects,
Func<T, TDisplayProperty> selectorDisplayMember,
Func<T, TSortProperty> selectorSortMember,
string delimiter,
// 1.) how to declare the delegate here as parameter ??
)
{
// pass here the delegate to a private field to save it
// 2.) how can I do that?
}
How can I do 1.) and 2.) ? :-)
UPDATE 2:
Ok thats what I have done so far:
public class SearchProvider<T>
{
public delegate IEnumerable<T> SearchInputTextStrategy<T>(string param);
public SearchInputTextStrategy<T> SearchStrategy { get; set; }
public T TypedValue
{
get
{
return (T)Convert.ChangeType(SearchStrategy, typeof(T));
}
}
}
UserControl:
public delegate IEnumerable<T> SearchInputTextStrategy<T>(string param);
public void BindElements<T, TDisplayProperty,TSortProperty>
(
IEnumerable<T> dataObjects,
Func<T, TDisplayProperty> selectorDisplayMember,
Func<T, TSortProperty> selectorSortMember,
string delimiter,
SearchInputTextStrategy<T> searchStrategy
)
{
/// assign the searchStrategy to the SearchProvider class
var sp = new SearchProvider<T>();
sp.SearchStrategy = searchStrategy // DOES NOT WORK !!!
}
Please read also my comments in the Code. What I want to achieve is pass the delegate to the searchProvider to save it somewhere... The code I write here I understand up to 50 % so please bear with me Generics are new to me although I use generic List for a long time ;P
UPDATE 2:
public partial class MainWindow : Window
{
public delegate IEnumerable SearchInputTextStrategy(string param);
private SearchInputTextStrategy<ICustomer> _strategy;
public MainWindow()
{
InitializeComponent();
IEnumerable<ICustomer> customers = DataService.GetCustomers();
_strategy = new SearchInputTextStrategy<ICustomer>(SearchCustomers);
ElementUserControl.BindElements(customers, c => c.FirstName, c => c.SortId, ";", _strategy);
namespace ElementTextBoxV2
{
public partial class MainWindow : Window
{
public delegate IEnumerable<ICustomer> SearchInputTextStrategy<ICustomer>(string param);
private SearchInputTextStrategy<ICustomer> _strategy;
public MainWindow()
{
InitializeComponent();
IEnumerable<ICustomer> customers = DataService.GetCustomers();
_strategy = new SearchInputTextStrategy<ICustomer>(SearchCustomers);
ElementUserControl.BindElements(customers, c => c.FirstName, c => c.SortId, ";", _strategy);
IEnumerable<ICustomer> selectedElements = ElementUserControl.SelectedElements<ICustomer>();
}
// Just a Test-Methode to assure the delegate works
public IEnumerable<ICustomer> SearchCustomers(string param)
{
IEnumerable<ICustomer> foundCustomers = new List<ICustomer>();
return foundCustomers;
}
}
}
The scenario is, that the user has put the TextBoxUserControl in a MainWindow and he has to pass a delegate pointing to a searchMethod. I have implemented this with the SearchCustomers_Method. The problem is that C# can not resolve that:
Error 1 The best overloaded method match for 'ElementTextBoxV2.ElementsView.BindElements<ElementTextBoxV2.ICustomer,string,int>(System.Collections.Generic.IEnumerable<ElementTextBoxV2.ICustomer>, System.Func<ElementTextBoxV2.ICustomer,string>, System.Func<ElementTextBoxV2.ICustomer,int>, string, ElementTextBoxV2.Provider.SearchInputTextStrategy<ElementTextBoxV2.ICustomer>)' has some invalid arguments
Error 2 Argument 5: cannot convert from 'ElementTextBoxV2.MainWindow.SearchInputTextStrategy<ElementTextBoxV2.ICustomer>' to 'ElementTextBoxV2.Provider.SearchInputTextStrategy<ElementTextBoxV2.ICustomer>'
Do you see the problem? In any case the User must pass a delegate with the same definition the BindElements Method has!
It's odd that your SearchInputTextStrategy has two type parameters but only actually uses one... but you just need to specify the type arguments in the parameter type. For example:
public void BindElements<T, TDisplayProperty,TSortProperty>
(
IEnumerable<T> dataObjects,
Func<T, TDisplayProperty> selectorDisplayMember,
Func<T, TSortProperty> selectorSortMember,
string delimiter,
SearchInputTextStrategy<T, TDisplayProperty> searchStrategy
)
I've only guessed at what the type arguments should be - you haven't really said what you want the parameter to represent.
You won't be able to easily have a field of the right type in your class, because the class itself doesn't know the type parameters involved. It's possible that you should really be making your class generic, or make another class which is able to handle the delegates appropriately. Without any more information, it's very hard to know which.
private SearchInputTextStrategy<T, string> _searchStrategy;
public void BindElements<T, TDisplayProperty,TSortProperty>
(
IEnumerable<T> dataObjects,
Func<T, TDisplayProperty> selectorDisplayMember,
Func<T, TSortProperty> selectorSortMember,
string delimiter,
SearchInputTextStrategy<T, string> searchStrategy
)
{
_searchStrategy = searchStrategy;
}
Related
I have classes which are derived from a base class and would like to instantiate these classes dynamically at run time. Using the following code, I can build a class using the default constructor:
public abstract class Employee : IEmployeeInterface
{
public string Name { get; set; }
public Employee() { }
public Employee(string name)
{
Name = name;
}
}
public static class EmployeeBot
{
static readonly Func<string, Func<Employee>> EmployeeBotFunction = x =>
Expression.Lambda<Func<Employee>>(
Expression.New(Type.GetType(x).GetConstructor(Type.EmptyTypes))
).Compile();
public static Employee InstantiateNewEmployee(string type)
{
string argumentType = string.Format("{1}.{0}", type.ToString(), MethodBase.GetCurrentMethod().DeclaringType.Namespace);
return EmployeeBotFunction(argumentType).Invoke();
}
}
Worker implements Employee and can be created using:
Employee employee = EmployeeBot.InstantiateNewEmployee("Worker");
Then, since Worker has all the same methods as Employee, calling them will give the results from the worker class as expected.
However, I cannot work out how to correctly implement similar code to use a constructor with arguments. For example:
static readonly Func<string, Type[], Func<string, Employee>> NewEmployee = (x, y) =>
Expression.Lambda<Func<string, Employee>>(
Expression.New(Type.GetType(x).GetConstructor(y))
).Compile();
public static Employee InstantiateNewEmployee(string type, string Name)
{
Type[] construct = new Type[] { typeof(string) };
string argumentType = string.Format("{1}.{0}", type.ToString(), MethodBase.GetCurrentMethod().DeclaringType.Namespace);
return NewEmployee(argumentType, construct).Invoke(Name);
}
Calling this method throws an exception:
EmployeesTests.InstantiateEmployeeWithName threw exception:
System.InvalidOperationException: Method may only be called on a Type
for which Type.IsGenericParameter is true.
How can the NewEmployee function be altered to accept the required parameters for the second constructor?
I have answered this with the help of #JSteward so thank you!
Combined with a different version of Expression.New and fixing a stupid mistake I was able to solve this. You cannot instance an abstract class so my constructor should have been on one of the derived classes, e.g public class Worker : Employee and not public abstract class Employee.
The actual error was that the constructor parameter to the Expression.New(Type.GetType(x).GetConstructor(y)); was null because it was not defined on the Worker.
The second example now becomes; (though I'm sure this can be improved!).
static readonly Func<string, Type[], ParameterExpression[], Func<string, Employee>> NewEmployee = (x, y, z) =>
Expression.Lambda<Func<string, Employee>>(
Expression.New(Type.GetType(x).GetConstructor(y), z)
, z).Compile();
public static Employee InstantiateNewEmployee(string type, string Name)
{
Type[] construct = new Type[] { typeof(string) };
string argumentType = string.Format("{1}.{0}", type.ToString(), MethodBase.GetCurrentMethod().DeclaringType.Namespace);
ParameterExpression[] arguments = new ParameterExpression[] { Expression.Parameter(typeof(string)) };
return NewEmployee(argumentType, construct, arguments).Invoke(Name);
}
The post from #JSteward 's comments actually generalises this requirement already: linq-expressions-creating-objects
I appreciate your help and also the comment from the blog.
But good to see that I’m not the only person crazy enough to be using Expressions in this way!
My code is as follows:
public partial class WhereHelper<T1> { }
public static partial class WhereHelperExtension
{
public static T Where<T,T1>(this T t, Expression<Func<T1,bool>> where) where T : WhereHelper<T1>
{
//do something....
return t;
}
}
public class Test
{
public void Main()
{
WhereHelper<DateTime> dt = new WhereHelper<DateTime>();
dt.Where(t => t.Year == 2016);//this is error
dt.Where<WhereHelper<DateTime>, DateTime>(t => t.Year == 2016);//this is success
}
}
Extension method I want to be like this:
WhereHelper<DateTime> dt = new WhereHelper<DateTime>();
dt.Where(t => t.Year == 2016);//this is error
how to create generic extension with Expression method.
Visual Studio does not recognize the "Where" extension methods.
In C#, if you need to provide any generic argument, you must provide them all. where constraints do not provide hints to the type resolver, and so it's impossible to decide what T1 is.
Change your signature to the following:
public static WhereHelper<T> Where<T>(this WhereHelper<T> t, Expression<Func<T,bool>> where)
{
return t;
}
Here, we know exactly what T, purely from the first argument, and so we do not have to explicitly specific the arguments.
Is there a way to pass a method name in a generic manner, without passing its parameters, so it can be invoked by the method, with passed arguments?
Consider this example:
public class Client
{
public string Convert(int value)
{
return value.ToString();
}
}
public class Wrapper<TClient>
{
TClient Client;
public TResult Invoke<TArg, TResult>(Func<TClient, TArg, TResult> action, TArg arg)
{
return action(Client, arg);
}
}
I want to be able to pass to the wrapper the method of TClient I want to invoke, and pass the actual arguments along, all generically:
var wrapper = new Wrapper<Client>();
wrapper.Invoke(c => c.Convert, 5);
Is there any possible way to achieve that, without hard coding the method name, or losing its genericness (i.e. by using Delegate)?
Notes:
The Client is an external sealed class that exposes a gazillion methods each of many parameters. I want wrap its behavior and I don't mind writing all the necessary code in the wrapper, but the usage of the wrapper should be as clean as possible.
Update
I want to avoid the need to specify the parameters. The whole idea is having them inferred from the specified action.
You're very close to getting your code to run. There are two options.
First, you can try this:
public class Wrapper<TClient>
{
public TResult Invoke<TArg, TResult>(Func<TArg, TResult> action, TArg arg)
{
return action(arg);
}
}
Then call it like this:
var wrapper = new Wrapper<Client>();
wrapper.Invoke(wrapper.client.Convert, 5);
Or, alternatively, you can do this:
public class Wrapper<TClient>
{
public Wrapper(TClient client)
{
this.Client = client;
}
private TClient Client;
public TResult Invoke<TArg, TResult>(Func<TClient, TArg, TResult> action, TArg arg)
{
if (operation.Target != Client)
throw new ArgumentException(nameof(operation));
return action(this.Client, arg);
}
}
And call it like this:
var client = new Client();
var wrapper = new Wrapper<Client>(client);
wrapper.Invoke((c, a) => c.Convert(a), 5);
But, from your description of your problem, I don't see how either of these help and I don't see how to implement what you're asking. Perhaps you need to provide more detail as to what the underlying need you're trying to solve?
You want the expression being passed to Invoke to return a Func that accepts TArg. In code:
public class Wrapper<TClient>
{
TClient Client;
public TResult Invoke<TArg, TResult>(Func<TClient, Func<TArg, TResult>> action, TArg arg)
{
return action(Client)(arg);
}
}
You can then invoke it like so:
class Program
{
static void Main(string[] args)
{
var wrapper = new Wrapper<Client>();
string result = wrapper.Invoke<int, string>(c => c.Convert, 5);
}
}
Since you don't like the approach of having to explicitly specify type arguments, you can use a slightly different API (which comes with its own annoyances):
public class Wrapper<TClient>
{
TClient Client;
public void Invoke<TArg, TResult>(Func<TClient, Func<TArg, TResult>> action, TArg arg, out TResult result)
{
return action(Client)(arg);
}
}
You can call this like so, with the return type inferred from the out parameter:
class Program
{
static void Main(string[] args)
{
var wrapper = new Wrapper<Client>();
string result;
wrapper.Invoke(c => c.Convert, 5, out result);
}
}
I've ended up with a situation where an function expression tree Expression<Func<TClass, TProperty>> is assigned to a global variable of type object and then later in the code I need to call a different method with the expression. I can't change the global objects type; it has to be object.
The code won't compile when trying to call the second method with the global object unless I cast the object as Expression<Func<TClass, TProperty>>. The problem is I don't know what TProperty is at the point that the second method is called.
I've created a quick demo app to illustrate the point (c# console app written in VS2010) - the real application looks nothing like this.
using System;
using System.Linq.Expressions;
namespace FuncExpressionTree
{
public class ViewModel
{
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
public class Helper<T>
where T : ViewModel
{
private object _global;
public void Execute()
{
AssignToGlobal((T vm) => vm.StringProperty);
ProcessGlobal();
AssignToGlobal((T vm) => vm.IntProperty);
ProcessGlobal();
}
public void AssignToGlobal<TClass, TProperty>(Expression<Func<TClass, TProperty>> expression)
{
_global = expression;
}
public void ProcessGlobal()
{
// invalid cast exception thrown when IntProperty is assigned to _global
AssignToGlobal((Expression<Func<T, string>>)_global);
}
}
class Program
{
static void Main(string[] args)
{
(new Helper<ViewModel>()).Execute();
}
}
}
If we focus on the Execute() method.
First global is assigned expression for the string property.
ProcessGlobal executes and works because I'm casting to Expression<Func<T, string>>.
Next global is assigned expression for int property.
ProcessGlobal again executes but its at this point that an invalid cast exception is thrown. It would work if I changed it to cast Expression<Func<T, int>> instead but then the string property wouldn't work. Also Expression<Func<T, object>> throws an invalid cast exception.
I feel like Im missing something and that it should be possible to do something with the System.Linq.Expressions namespace to dynamically invoke the the second method (eg AssignToGlobal within ProcessGlobal in the above example).
So how can I get this to work in a generic way?
public void ProcessGlobal()
{
var globalType = _global.GetType(); // globalType = Expression<Func<TClass, TProperty>>
var functionType = globalType.GetGenericArguments()[0]; // functionType = Func<TClass, TProperty>
var functionGenericArguments = functionType.GetGenericArguments(); // v = [TClass, TProperty]
var method = this.GetType().GetMethod("AssignToGlobal").MakeGenericMethod(functionGenericArguments); //functionGenericArguments = AssignToGlobal<TClass, TProperty>
method.Invoke(this, new[] { this._global }); // Call AssignToGlobal<TClass, TProperty>)(this._global);
}
I've started using C# Expression constructs, and I've got a question about how generics are applied in the following situation:
Consider I have a type MyObject which is a base class for many different types. Inside this class I have the following code:
// This is a String Indexer Expression, used to define the string indexer when the object is in a collection of MyObjects
public Expression<Func<MyObject, string, bool>> StringIndexExpression { get; private set;}
// I use this method in Set StringIndexExpression and T is a subtype of MyObject
protected void DefineStringIndexer<T>(Expression<T, string, bool>> expresson) where T : MyObject
{
StringIndexExpression = expression;
}
This is how I use DefineStringIndexer:
public class MyBusinessObject : MyObject
{
public string Name { get; set; }
public MyBusinessObject()
{
Name = "Test";
DefineStringIndexer<MyBusinessObject>((item, value) => item.Name == value);
}
}
However in the assignment inside DefineStringIndexer I get the compile error:
Cannot implicitly convert type
System.Linq.Expression.Expression< MyObject, string, bool > to
System.Linq.Expression.Expression < MyBusinessObject, string, bool >>
Can I use Generics with C# Expressions in this situation? I want to use T in DefineStringIndexer so I can avoid casting MyObject inside the lambda.
The assignment will not work, because the Func<MyBusinessObject,string,bool> type is not assignment-compatible with Func<MyObject,string,bool>. However, the parameters of the two functors are compatible, so you can add a wrapper to make it work:
protected void DefineStringIndexer<T>(Func<T,string,bool> expresson) where T : MyObject {
StringIndexExpression = (t,s) => expression(t, s);
}
Would this work better for you?
Edit: Added <T> to constraint - think you will need that :)
class MyObject<T>
{
// This is a String Indexer Expression, used to define the string indexer when the object is in a collection of MyObjects
public Expression<Func<T, string, bool>> StringIndexExpression { get; private set;}
// I use this method in Set StringIndexExpression and T is a subtype of MyObject
protected void DefineStringIndexer<T>(Expression<T, string, bool>> expresson)
where T : MyObject<T> // Think you need this constraint to also have the generic param
{
StringIndexExpression = expression;
}
}
then:
public class MyBusinessObject : MyObject<MyBusinessObject>
{
public string Name { get; set; }
public MyBusinessObject()
{
Name = "Test";
DefineStringIndexer<MyBusinessObject>((item, value) => item.Name == value);
}
}