Passing parameter to method returning Func - c#

I have the following static class
public static partial class ClassX
{
private static readonly Expression<Func<Customer, CustomerDetail>> _exp = DoX();
private static readonly Func<Customer, CustomerDetail> _comp = DoX().Compile();
static ClassX() { }
public static IQueryable<CustomerDetail> ConvertDetail(this IQueryable<Customer> query)
{
query.Select(_exp);
}
public static CODEDistrictDTO ConvertDetail(this Customer customer)
{
return _comp(customer);
}
private static Expression<Func<CODEDistrictEntity, CODEDistrictDTO>> DoX()
{
}
}
What I need to do is passing a parameter to "DoX" method through the method "ConvertDetail", so the "DoX" method build the logic base on the received parameter
public static partial class ClassX
{
private static readonly Expression<Func<Customer, CustomerDetail>> _exp = DoX(); //problem
private static readonly Func<Customer, CustomerDetail> _comp = DoX().Compile(); //problem
static ClassX() { }
public static IQueryable<CustomerDetail> ConvertDetail(this IQueryable<Customer> query, List<int> mlist)
{
query.Select(_exp(mlist));
}
public static CODEDistrictDTO ConvertDetail(this Customer customer, List<int> mlist)
{
return _comp(customer,mlist);
}
private static Expression<Func<CODEDistrictEntity, CODEDistrictDTO>> DoX(List<int> mlist)
{
}
}
The problem in the static readonly fields!!!

Take another look at the syntax for how a Func<> is defined:
https://learn.microsoft.com/en-us/dotnet/api/system.func-2
https://learn.microsoft.com/en-us/dotnet/api/system.func-3
public delegate TResult Func<in T,out TResult>(T arg);
public delegate TResult Func<in T1,in T2,out TResult>(T1 arg1, T2 arg2);
The definition you have applied at the top for Func<Customer, CustomerDetail> then means that you are providing a delegate function that takes in one parameter of type Customer and returns a result of type CustomerDetail. This following block calls the delegate function _comp with the customer value as that parameter.
public static CODEDistrictDTO ConvertDetail(this Customer customer)
{
return _comp(customer); // <- Calls our delegate Func<Customer,CustomerDetail> with a Customer param, returns a CustomerDetail
}
In your updated code, you suddenly start trying to pass two parameters to that delegate function with _comp(customer,mlist), but it is only defined as having one. To change the delegate to expect two parameters, with the second being of type List<int>, then you would need to update that to private static readonly Func<Customer, List<int>, CustomerDetail> _comp = ...
Keep in mind this is only going to help you if your DoX.Compile() method will actually accept this signature - updating the Func does not mean your provided delegate will suddenly know what to do with the extra parameter if it doesn't already expect it.

Related

Can we call a Static method of an Abstract Class using a generic Method? [duplicate]

How do I call a static method from a Type, assuming I know the value of the Type variable and the name of the static method?
public class FooClass {
public static FooMethod() {
//do something
}
}
public class BarClass {
public void BarMethod(Type t) {
FooClass.FooMethod() //works fine
if (t is FooClass) {
t.FooMethod(); //should call FooClass.FooMethod(); compile error
}
}
}
So, given a Type t, the objective is to call FooMethod() on the class that is of Type t. Basically I need to reverse the typeof() operator.
You need to call MethodInfo.Invoke method:
public class BarClass {
public void BarMethod(Type t) {
FooClass.FooMethod(); //works fine
if (t == typeof(FooClass)) {
t.GetMethod("FooMethod").Invoke(null, null); // (null, null) means calling static method with no parameters
}
}
}
Of course in the above example you might as well call FooClass.FooMethod as there is no point using reflection for that. The following sample makes more sense:
public class BarClass {
public void BarMethod(Type t, string method) {
var methodInfo = t.GetMethod(method);
if (methodInfo != null) {
methodInfo.Invoke(null, null); // (null, null) means calling static method with no parameters
}
}
}
public class Foo1Class {
static public Foo1Method(){}
}
public class Foo2Class {
static public Foo2Method(){}
}
//Usage
new BarClass().BarMethod(typeof(Foo1Class), "Foo1Method");
new BarClass().BarMethod(typeof(Foo2Class), "Foo2Method");
Note, that as 10 years have passed. Personally, I would add extension method:
public static TR Method<TR>(this Type t, string method, object obj = null, params object[] parameters)
=> (TR)t.GetMethod(method)?.Invoke(obj, parameters);
and then I could call it with:
var result = typeof(Foo1Class).Method<string>(nameof(Foo1Class.Foo1Method));
Check into the MethodInfo class and the GetMethod() methods on Type.
There are a number of different overloads for different situations.

How to call method with Func<string, T> as one of parameter

I have a class RemoteData like below,
public class RemoteData
{
public RemoteData(string Message, string IP)
{
this.IP = IP;
this.Message = Message;
}
public string IP;
public string Message;
}
Now I have a IObservable<T> method UdpStream like below,
public static IObservable<RemoteData> UdpStream(IPEndPoint endpoint, Func<string, RemoteData> processor)
{
return Observable.Using(() => new UdpClient(endpoint),
udpClient => Observable.Defer(() =>
udpClient.ReceiveAsync().ToObservable()).Repeat().Select(result => processor(Encoding.UTF8.GetString(result.Buffer))));
}
Now how to call UdpStream, how to pass Func parameter?
var stream = UdpStream(new IPEndPoint(IPAddress.Any, 514), 2nd Param);
Func<T, U> represents a delegate that takes a T parameter and returns U. You can initialize a Func<T, U> using a method reference that matches that signature, or using a lambda expression.
Using a Func<,> as parameter is a common idiom for a callback. For example, if you have a method similar to this:
public static void Method(Func<T, U> func)
{
// ...
}
We can expect that Method will call whaterver you pass in the func parameter. In fact, this happens in the code your present (the parameter Func<string, RemoteData> processor is called where it says processor(Encoding.UTF8.GetString(result.Buffer))).
Now, you have Func<string, RemoteData>, thus you need a method that takes string and returns RemoteData. For example:
public static RemoteData Example(string input)
{
// ...
}
// ...
var observable = UdpStream(endpoint, Example);

Ambiguous constructor call error

I have a class called Test which has a constructor to accept Action<T> and the other one accepts Func<T,T>. Please see the below snippet.
public class Test<T>
{
//constructors
public Test() { }
public Test(Action<T> action) { }
public Test(Func<T, T> action) { }
//methods with same signature of constructor
public void MyMethod1(Action<T> action) { }
public void MyMethod2(Func<T, T> action) { }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Test<string> t1 = new Test<string>(this.MyMethod1);
Test<string> t2 = new Test<string>(this.MyMethod2);
Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);
}
public void MyMethod1(string value) { }
public string MyMethod2(string value) { return string.Empty; }
}
But below lines throws an ambiguous call error
Test<string> t1 = new Test<string>(this.MyMethod1);
Test<string> t2 = new Test<string>(this.MyMethod2);
and the interesting point is, I have two methods with the same signature of my Test class constructor which not throwing any ambiguous error
Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);
Could anyone please help me to identify and fix the issue.
The return value of a method is not part of its signature. Only the parameters are considered. Hence, the compiler cannot distinguish between Action<T> and Func<T,T>. A detailed explanation and workarounds can be found in this StackOverflow question
You can try renaming the parameters for each of your constructors like so:
public class Test<T>
{
public Test() { }
public Test(Action<T> action) { }
public Test(Func<T,T> function) { }
}
So when you instantiate your class you can specify the name of the parameter like so:
var objectWithAction = new Test<string>(action: Method1);
var objectWithFunction = new Test<string>(function: Method2);
Fact
method / constructor overloading can recognize the correct method by the parameter types but does not include the return type.
Reason
And since in both of the mentioned constructor calls in the question the parameter is of type MethodGroup so the compiler is unable to determine the correct overload. secondly calls to the method are successful as that in not an overloading scenario.
Resolution
here are the possible options to solve the issue
wrapping the method call into an anonymous method call and let the implicit conversion to distinguish themselves.
Test<string> t1 = new Test<string>(s => this.MyMethod1(s));
Test<string> t2 = new Test<string>(s => { return this.MyMethod2(s); });
result
Alternate approach
other option is to explicitly cast the method group
Test<string> t1 = new Test<string>((Action<string>)this.MyMethod1);
Test<string> t2 = new Test<string>((Func<string, string>)this.MyMethod2);
this is bit longer then the first approach if parameters are less
here a working console application sample
class Program
{
static void Main(string[] args)
{
Test<string> t1 = new Test<string>(action: MyMethod1);
Test<string> t2 = new Test<string>(function: MyMethod2);
Test<string> t = new Test<string>();
t.MyMethod1(MyMethod1);
t.MyMethod2(MyMethod2);
}
public static void MyMethod1(string value)
{
Console.WriteLine("my method1 {0}", value);
}
public static string MyMethod2(string value)
{
Console.WriteLine("my method2 {0}", value);
return string.Empty;
}
}
public class Test<T>
{
//constructors
public Test() { }
public Test(Action<T> action)
{
object args = "action";
action.Invoke((T)args); // here you should invoke the method in order to execute it
}
public Test(Func<T, T> function)
{
object args = "function";
function.Invoke((T)args);
}
//methods with same signature of constructor
public void MyMethod1(Action<T> action)
{
object args = "Method 3";
action.Invoke((T)args);
}
public void MyMethod2(Func<T, T> action)
{
object args = "Method 4";
action.Invoke((T)args);
}
}
hope it will help you
regards

dynamic delegate to pass a method as parameter in C#

Is there any way to use DLR to reference a method in C#?
In dynamic languages like JavaScript or Python I could easily pass a method as an argument to another method. In C# being statically typed language, I either use Delegate type which needs lots of casting:
public static void AddMethod(Delegate del)
{
// implementation
}
and then use casting whenever I call this method
static void Main(string[] args)
{
AddMethod(new Func<object, bool>(Test));
}
public static bool Test(object obj)
{
return true;
}
Or, I need to define dozens of overloads to satisfy any method calls:
public static void AddMethod<TResult>(Func<TResult> method)
{
}
public static void AddMethod<T, TResult>(Func<T, TResult> method)
{
}
public static void AddMethod<T1, T2, TResult>(Func<T1, T2, TResult> method)
{
}
public static void AddMethod<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> method)
{
}
Is there any cleaner way to define an argument as a placeholder for all other methods? (I'm trying to avoid MethodInfo or other Reflection stuff here)
I was trying something like this:
public delegate dynamic DynamicDelegate(params dynamic[] args);
public static void AddMethod(DynamicDelegate method)
{
}
But the compiler doesn't seem to accept a statically typed method for a dynamically declared delegates!
Any other thoughts?
You can use a simple Action
void AddMethod(Action action) //or void AddMethod(Func<TResult> fxn)
{
}
and call as
AddMethod(()=>Test(obj));
or
AddMethod(()=>Test(obj1,obj2));
--EDIT--
AddMethod(() => Math.Max(1,3));
AddMethod(() => (int)Math.Sqrt(4));
AddMethod(() => new int[]{8,5,6}.Min())
void AddMethod(Func<int> fxn)
{
int i = fxn() * fxn(); // <---
}
Since .NET doesn't allow delegates with an unknown parameter syntax (this would approximate C void pointers, which is not something you want in a type-safe language), the closest thing that allows a variable argument list would be to pass an array of object arguments (i.e. object MyMethod(params object[] args)).
However, since this array is also an object reference, you can suffice with a single object reference:
object MyMethod(object arg))
The .NET framework also does this, see e.g. the ParameterizedThreadStart delegate)
So the basic idea is that you require that the user writes his code as a method that matches the above signature, and in turn it can receive any variable list of arguments of any type or size.
see below
Logger coreLogger;
Logger coreErrorLogger;
public Core()
{
PassByReference timestamp = new PassByReference(Timestamp);
coreLogger = Logger.GetLogger("LiTHiuM Core");
coreLogger.SetFormat("[{0}][LiTHiuM Core]: ", timestamp);
coreLogger.AddLogger(Log);
coreErrorLogger = Logger.GetLogger("LiTHiuM Core Error");
coreErrorLogger.SetFormat("[{0}][LiTHiuM Core (ERROR)]: ", timestamp);
coreErrorLogger.AddLogger(Error);
}
public string Timestamp(params dynamic[] args)
{
return DateTime.Now.ToString();
}
public delegate dynamic Reference(params dynamic[] args);
public class PassByReference
{
Reference reference;
public PassByReference(Reference reference)
{
this.reference = reference;
}
public override string ToString()
{
return this.reference().ToString();
}
}
public class Logger
{
static Dictionary<string, Logger> logFormatDict = new Dictionary<string, Logger>();
private List<LoggerDelegate> loggerDelegates = new List<LoggerDelegate>();
public static Logger GetLogger(string name)
{
if (logFormatDict.ContainsKey(name))
{
return logFormatDict[name];
}
else
{
var newLogFormat = new Logger(name, "");
logFormatDict.Add(name, newLogFormat);
return newLogFormat;
}
}
private event LoggerDelegate loggingEvent;
private Logger(string name, string format, params dynamic[] args)
{
this.Name = name;
this.format = format;
this.args = args;
}
public void AddLogger(LoggerDelegate logger)
{
if (!loggerDelegates.Contains(logger))
{
loggingEvent += logger;
loggerDelegates.Add(logger);
}
}
public void RemoveLogger(LoggerDelegate logger)
{
if (loggerDelegates.Contains(logger))
{
loggingEvent -= logger;
loggerDelegates.Remove(logger);
}
}
public void Log(string text, params dynamic[] args)
{
this.Invoke(String.Format(text, args));
}
public void Invoke(string text, params dynamic[] args)
{
loggingEvent.Invoke(this.ToString() + text, args);
}
public void SetFormat(string format, params dynamic[] args)
{
this.args = args;
this.format = format;
}
public string Name
{
get;
set;
}
string format;
dynamic[] args;
public override string ToString()
{
return String.Format(format, args);
}
}

Calling a static method using a Type

How do I call a static method from a Type, assuming I know the value of the Type variable and the name of the static method?
public class FooClass {
public static FooMethod() {
//do something
}
}
public class BarClass {
public void BarMethod(Type t) {
FooClass.FooMethod() //works fine
if (t is FooClass) {
t.FooMethod(); //should call FooClass.FooMethod(); compile error
}
}
}
So, given a Type t, the objective is to call FooMethod() on the class that is of Type t. Basically I need to reverse the typeof() operator.
You need to call MethodInfo.Invoke method:
public class BarClass {
public void BarMethod(Type t) {
FooClass.FooMethod(); //works fine
if (t == typeof(FooClass)) {
t.GetMethod("FooMethod").Invoke(null, null); // (null, null) means calling static method with no parameters
}
}
}
Of course in the above example you might as well call FooClass.FooMethod as there is no point using reflection for that. The following sample makes more sense:
public class BarClass {
public void BarMethod(Type t, string method) {
var methodInfo = t.GetMethod(method);
if (methodInfo != null) {
methodInfo.Invoke(null, null); // (null, null) means calling static method with no parameters
}
}
}
public class Foo1Class {
static public Foo1Method(){}
}
public class Foo2Class {
static public Foo2Method(){}
}
//Usage
new BarClass().BarMethod(typeof(Foo1Class), "Foo1Method");
new BarClass().BarMethod(typeof(Foo2Class), "Foo2Method");
Note, that as 10 years have passed. Personally, I would add extension method:
public static TR Method<TR>(this Type t, string method, object obj = null, params object[] parameters)
=> (TR)t.GetMethod(method)?.Invoke(obj, parameters);
and then I could call it with:
var result = typeof(Foo1Class).Method<string>(nameof(Foo1Class.Foo1Method));
Check into the MethodInfo class and the GetMethod() methods on Type.
There are a number of different overloads for different situations.

Categories

Resources