How cast Generic T to Action<...> to get the Method params - c#

Hi i'm try to cast a generic to an Action with a unknown number and type of Parameters
at the moment it looks like:
public class subscriber
{
public subscriber()
{
new Subscription<Action>(a);
new Subscription<Action<string>>(b);
new Subscription<Action<int,string>>(c);
}
private void a() { }
private void b(string gg){}
private void c(int i, string g) { }
}
public class Subscription<T>
{
public T MyAction {get {retun _action;}}
public Type MyActionType {get;private set;}
public Subscription( T action )
{
MyAction = action;
MyActionType = action.GetType();
var gg = action.GetType().GetGenericArguments();// Contains the Sub generics
}
}
at the moment we know it will be an Action and we also know the Sub Types but how to put this all together
to execute my private void c(int i, string g) method
Final Goal
is to execute the Action from a Third-Class (which will contains a List<Subscription> ) when a Fourth-Class hand over some params

public abstract class SubscriptionBase
{
public abstract void ExecuteAction(params object[] parameters);
}
public class Subscription<T> : SubscriptionBase
{
private T _action;
public Subscription(T a)
{
_action = a;
}
public override void ExecuteAction(params object[] parameters)
{
(_action as Delegate).DynamicInvoke(parameters);
}
}
and you can use it like;
Action<int> func1 = (q) => q += 1;
Action<int, int> func2 = (q, w) => q += w;
Subscription<Action<int>> s1 = new Subscription<Action<int>>(func1);
Subscription<Action<int, int>> s2 = new Subscription<Action<int, int>>(func2);
List<SubscriptionBase> subscriptionBase = new List<SubscriptionBase>();
subscriptionBase.Add(s1);
subscriptionBase.Add(s2);
subscriptionBase[1].ExecuteAction(1, 2);

You can't do it that way. You can't put a Subscription<Action<int>> into the same list as Subscription<Action<string, Foo>>.
I suggest, you create an interface like the following and store those in your third class:
interface IActionExecutor
{
bool CanExecuteForParameters(params object[] parameters);
void Execute(params object[] parameters);
}
// Implementation for one parameter
// You need to create one class per additional parameter.
// This is similar to the Action delegates in the framework.
// You can probably extract a base class here that implements
// some of the repetitive pars
public class ActionExecutor<in T> : IActionExecutor
{
private Action<T> _action;
public ActionExecutor(Action<T> action)
{
if(action == null) throw new ArgumentNullException("action");
_action = action;
}
public bool CanExecuteForParameters(params object[] parameters)
{
if(parameters == null) throw new ArgumentNullException("action");
if(parameters.Length != 1) return false;
return parameters[0] is T;
}
public void Execute(params object[] parameters)
{
if(parameters == null) throw new ArgumentNullException("action");
if(parameters.Length != 1)
throw new ArgumentOutOfRangeException("action");
_action((T)parameters[0]);
}
}
In your third class you would have the list of IActionExecutors:
List<IActionExecutor> _subscriptions;
And you would use it like this:
public void Execute(params object[] parameters)
{
var matchingSubscriptions =
_subscriptions.Where(x => x.CanExecuteForParameters(parameters);
foreach(var subscription in matchingSubscriptions)
subscription.Execute(parameters);
}
To simplify the creation of those ActionExecutor instances, you can provide a factory class:
public static class ActionExecutor
{
public IActionExecutor Create(Action action)
{
return new ActionExecutor(action);
}
public IActionExecutor Create<T>(Action<T> action)
{
return new ActionExecutor<T>(action);
}
public IActionExecutor Create<T1, T2>(Action<T1, T2> action)
{
return new ActionExecutor<T1, T2>(action);
}
// ... and so on
}
Usage would now be like this:
_subscriptions.Add(ActionExecutor.Create(a));
_subscriptions.Add(ActionExecutor.Create(b));
_subscriptions.Add(ActionExecutor.Create(c));

Related

How to pass a Func<> property/method to a NancyFx Get() method?

The NancyFx (2.x) NancyModule.Get() method is defined as:
public virtual void Get(string path, Func<dynamic, object> action, [Func<NancyContext, bool> condition = null], [string name = null]);
The normal usage is:
public class MyModule
{
public MyModule()
{
this.Get("/", parameters => {
this.RequestHandler = new RequestHandler();
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
});
}
}
I want to define the second parameter as a property, so that I can use for several paths like this:
public class MyModule
{
Func<dynamic, object> indexHandler = parameters => {
// Error: Keyword "this" is not available in this context
this.RequestHandler = new RequestHandler();
// Error: Keyword "this" is not available in this context
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
};
public MyModule()
{
this.Get("/", indexHandler);
this.Get("/index", indexHandler);
}
}
If I do this it works:
public class MyModule
{
public MyModule()
{
Func<dynamic, object> indexHandler = parameters => {
this.RequestHandler = new RequestHandler();
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
};
this.Get("/", indexHandler);
this.Get("/index", indexHandler);
}
}
But I don't want to define it in the constructor. What am I doing wrong? Is there any other way to do this?
MVCE
Dependancy Package: Nancy (Version: 2.0.0-clinteastwood)
using Nancy;
using Nancy.Responses.Negotiation;
namespace MyNamespace
{
public class MyModule : NancyModule
{
private RequestHandler RequestHandler;
private object IndexHandler(dynamic parameters)
{
this.RequestHandler = new RequestHandler();
var someOtherInfo = "";
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
}
public MyModule()
{
this.Get("/", IndexHandler);
this.Get("/index", IndexHandler);
this.Get("/home", parameters => {
return this.Negotiate.WithView("myview.html");
});
}
}
public class RequestHandler
{
public Negotiator HandleRequest(string path, dynamic parameters, string someOtherInfo)
{
return new Negotiator(new NancyContext());
}
}
}
This should work:
public class MyModule
{
public MyModule()
{
this.Get("/", IndexHandler);
this.Get("/index", IndexHandler);
}
private object IndexHandler(dynamic parameters) {
this.RequestHandler = new RequestHandler();
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
}
}
Andrew's answer is valid and should've been sufficient but apparently (in your MVCE) that method definition doesn't exist.
Here's the correct definition (at least the one VS wants):
public virtual void Get(string path, Func<object, Task<object>> action, Func<NancyContext, bool> condition = null, string name = null)
Luckly your HandleRequest is awaitable so you only need to edit the return type.
Here's the correct definition:
private Task<object> IndexHandler(dynamic parameters)
{
this.RequestHandler = new RequestHandler();
var someOtherInfo = "";
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
}
Hope this helps!

Polymorphic object creation without IF condition

I have an abstract class like this:
public abstract class Records
{
public string Type;
public string Source;
public int Value;
protected Records(string type, string source, int value)
{
Type = type;
Source = source;
Value = value;
}
}
I would like to create many classes inheriting this class, and filling their Type field with a value coming from a static class like this:
public static class ContentTypesString
{
public static string DocumentNew { get { return "Document - New this Month"; }}
public static string HeadlinesNew { get { return "Headlines - New this Month"; }}
etc...
}
I would like to be able to create those child classes without having a test "if foo == "document" then type = ContentTypesString.DocumentNew" or an equivalent switch case (I really have a lot of cases)
Is there a design pattern that suits my needs?
EDIT : As several people pointed out, i should show how i create my instances.
private delegate SPListItemCollection Query(SPWeb web, DateTime startDate, DateTime endDate);
private readonly Query _queries;
#region Constructors
public QueryHandler(SPWeb web, DateTime startTimeSelectedDate, DateTime endTimeSelectedDate)
{
if (web == null) throw new ArgumentNullException("web");
_web = web;
_startTimeSelectedDate = startTimeSelectedDate;
_endTimeSelectedDate = endTimeSelectedDate;
RecordsList = new List<Records>();
// Query Invocation List
_queries = NumberPagePerMonthQuery.PreparedQuery;
_queries += NumberDocumentsPerMonthQuery.PreparedQuery;
_queries += NumberHeadlinesPerMonthQuery.PreparedQuery;
_queries += NumberLeaderboxPerMonthQuery.PreparedQuery;
_queries += NumberNewsPerMonthQuery.PreparedQuery;
_queries += NumberPagesModifiedPerMonthQuery.PreparedQuery;
_queries += NumberPicturesPerMonthQuery.PreparedQuery;
_queries += NumberTeasingPerMonthQuery.PreparedQuery;
}
#endregion Constructors
#region Public Methods
// what about NullReferenceException ? C#6 : item?.Foreach(item => {}); ?
/*** NO C#6 compiler in VS2012... ***/
public void Queries()
{
foreach (var del in _queries.GetInvocationList())
{
var queryresult =
(SPListItemCollection) del.DynamicInvoke(_web, _startTimeSelectedDate, _endTimeSelectedDate);
RecordsList.Add(new Records(del.Method.Name, _web.Title, queryresult.Count));
}
}
EDIT² :
The solution i chose
public List<IQuery> QueryList { get; } // no delegate anymore, and static classes became implementations of IQuery interface.
#region Constructors
public QueryHandler(SPWeb web, DateTime startTimeSelectedDate, DateTime endTimeSelectedDate)
{
if (web == null) throw new ArgumentNullException("web");
_web = web;
_startTimeSelectedDate = startTimeSelectedDate;
_endTimeSelectedDate = endTimeSelectedDate;
RecordsList = new List<Records>();
QueryList = new List<IQuery>
{
new NumberDocumentsPerMonthQuery(),
new NumberHeadlinesPerMonthQuery(),
new NumberLeaderboxPerMonthQuery(),
new NumberNewsPerMonthQuery(),
new NumberPagePerMonthQuery(),
new NumberPagesModifiedPerMonthQuery(),
new NumberPicturesPerMonthQuery(),
new NumberTeasingPerMonthQuery()
};
}
#endregion Constructors
#region Public Methods
// what about NullReferenceException ? C#6 : item?.Foreach(item => {}); ?
/*** NO C#6 compiler in VS2012... ***/
public void Queries()
{
foreach (var query in QueryList)
{
var queryresult = query.PreparedQuery(_web, _startTimeSelectedDate, _endTimeSelectedDate);
RecordsList.Add(query.CreateRecord(_web.Title, queryresult.Count));
}
}
Record class follow the implementation suggested by #dbraillon
Implementation of IQuery interface were added the method :
public Records CreateRecord(string source, int value)
{
return new ModifiedPagesPerMonthRecord(source, value); //or another child of Record class.
}
And voilĂ . Thank you all for the help.
You want to make collection of records, by string code of object type, and parameters.
One of many way to do it - use builder.
Firstly we need to configurate builder:
var builder = new RecordBuilder()
.RegisterBuilder("document", (source, value) => new Document(source, value))
.RegisterBuilder("headlines", (source, value) => new Headlines(source, value));
here we specify how to build record with code "document" and "headlines".
To build a record call:
builder.Build("document", "source", 1);
Builder code can by something like this
(here we look if we know how to build record of the passed type and make it):
public class RecordBuilder
{
public Records Build(string code, string source, int value)
{
Func<string, int, Records> buildAction;
if (recordBuilders.TryGetValue(code, out buildAction))
{
return buildAction(source, value);
}
return null;
}
public RecordBuilder RegisterBuilder(string code, Func<string, int, Records> buildAction)
{
recordBuilders.Add(code, buildAction);
return this;
}
private Dictionary<string, Func<string, int, Records>> recordBuilders = new Dictionary<string, Func<string, int, Records>> ();
}
public class Document : Records
{
public Document(string source, int value) : base(ContentTypesString.DocumentNew, source, value)
{
}
}
public class Headlines : Records
{
public Headlines(string source, int value) : base(ContentTypesString.HeadlinesNew, source, value)
{
}
}
Is that what you need ?
public abstract class Records
{
public string Type;
public string Source;
public int Value;
protected Records(string type, string source, int value)
{
Type = type;
Source = source;
Value = value;
}
}
public class DocumentRecords : Records
{
public DocumentRecords(string source, int value)
: base(ContentTypesString.DocumentNew, source, value) // use here
{
}
}
public class HeadlinesRecords : Records
{
public HeadlinesRecords(string source, int value)
: base(ContentTypesString.HeadlinesNew, source, value) // use here
{
}
}
public static class ContentTypesString
{
public static string DocumentNew { get { return "Document - New this Month"; } }
public static string HeadlinesNew { get { return "Headlines - New this Month"; } }
}

switching on type in c# and VB - is this approach stupid?

I have inherited a codebase which contains a lot of upcasting.
I've got tired of all of the switch statements on types with ad-hoc casts inside the code.
I wrote a couple of functions for switching on the type of a variable and getting access to to that variable appropriately cast in the corresponding "case" statement.
As I am relatively new to dot net I thought that perhaps I was coming at it from completely the wrong angle.
If I'm not perhaps this will be useful to someone else.
NB c# specific answers are less useful as the code-base is mostly Visual Basic. I have posted c# code because the c# community is much larger here on stackexchange.
This is an example of the usage:
class Program
{
static void Main(string[] args)
{
List<object> bobbies = new List<object>();
bobbies.Add(new Hashtable());
bobbies.Add(string.Empty);
bobbies.Add(new List<string>());
bobbies.Add(108);
bobbies.Add(10);
bobbies.Add(typeof(string));
bobbies.Add(typeof(string));
bool b = true;
// as an expression
foreach (var bob in bobbies)
Console.WriteLine(
TypeSwitch.on<String>(bob)
.inCase<Hashtable>(x =>
"gotta HASHTABLE")
.inCase<string>(x =>
"its a string " + x)
.inCase<IEnumerable<Object>>(x =>
"I got " + x.Count<Object>().ToString() + " elements")
.inCase<int>(x => (x > 10), x =>
"additional conditions")
.inCase(b, x => {
b = false;
return "non lazy conditions"; })
.otherwise(p =>
"default case"));
// as a statement
foreach (var bob in bobbies)
TypeSwitch.on(bob)
.inCase<Hashtable>(x => Console.WriteLine("one"))
.inCase<String>(x => Console.WriteLine("two"))
.inCase<int>(x => Console.WriteLine("three"))
.otherwise(x => Console.WriteLine("I give up"));
Console.ReadLine();
}
}
and here is the implementation
public static class TypeSwitch
{
public class TypeSwitcher
{
private object _thing;
public TypeSwitcher(object thang) { _thing = thang; }
public TypeSwitcher inCase<TryType>(Func<TryType, bool> guard, Action<TryType> action) {
if (_thing is TryType) {
var t = (TryType)_thing;
if (guard(t)) {
_thing = null;
action(t); } }
return this; }
public TypeSwitcher inCase<TryType>(bool condition, Action<TryType> action) { return inCase<TryType>(p => condition, action); }
public TypeSwitcher inCase<TryType>(Action<TryType> action) { return inCase<TryType>(true, action); }
public TypeSwitcher inCase(bool cond, Action<object> action) { return inCase<object>(cond, action); }
public void otherwise(Action<object> action) { this.inCase<object>(action); }
}
// for case statements with a return value:
public class TypeSwitcherExpression<ResultType>
{
private object _thing;
private ResultType _result;
public ResultType Result { get { return _result; } }
public TypeSwitcherExpression(object thang) { _thing = thang; }
public TypeSwitcherExpression<ResultType> inCase<TryType>(Func<TryType, bool> guard, Func<TryType, ResultType> action) {
if (_thing is TryType) {
var t = (TryType)_thing;
if (guard(t)) {
_thing = null;
_result = action(t); } }
return this; }
public TypeSwitcherExpression<ResultType> inCase<TryType>(bool condition, Func<TryType, ResultType> action) { return inCase<TryType>(p => condition, action); }
public TypeSwitcherExpression<ResultType> inCase<TryType>(Func<TryType, ResultType> action) { return inCase<TryType>(true, action); }
public TypeSwitcherExpression<ResultType> inCase(bool cond, Func<object, ResultType> action) { return inCase<object>(cond, action); }
public ResultType otherwise(Func<object, ResultType> action) { this.inCase<object>(action); return Result; }
}
static public TypeSwitcher on(object thing)
{ return new TypeSwitcher(thing); }
static public TypeSwitcherExpression<ResultType> on<ResultType>(object thing)
{ return new TypeSwitcherExpression<ResultType>(thing); }
public static TypeSwitcher switchOnType(this Object thing)
{ return new TypeSwitcher(thing); }
public static TypeSwitcherExpression<ResultType> switchOnType<ResultType>(this Object thing)
{ return new TypeSwitcherExpression<ResultType>(thing); }
}
Edit 1:
Replaced delegates with Action and Func. Added extension method in case you like that sort of thing.
Edit 2:
Use Is to check type of object
Here is my suggestion
namespace xx{
public static class TypeSwitcher
{
public static dynamic inCase<T>(this object item,Func<dynamic> function)
{
if (item.GetType() == typeof(T))
return function();
else
return "";
}
}
}
using xx;
static void Main(string[] args)
{
List<object> bobbies = new List<object>();
bobbies.Add(new Hashtable());
bobbies.Add(string.Empty);
bobbies.Add(new List<string>());
bobbies.Add(108);
bobbies.Add(10);
bobbies.Add(typeof(string));
bobbies.Add(typeof(string));
foreach (var item in bobbies)
{
Console.WriteLine(item.inCase<Hashtable>(() => "one"));
Console.WriteLine(item.inCase<String>(() => "two"));
Console.WriteLine(item.inCase<int>(() => "three"));
}
Console.ReadLine();
}

Pass function as a parameter to Action

I am trying to pass a method as an action, but it seems that that the casting is not per say.
This is how I am doing it:
public class RequestHandler<T> where T : struct
{
public enum EmployeeRequests { BasicDetails, DependentsAndEmergencyContacts , MedicalHistory }
protected Dictionary<T, Action> handlers = new Dictionary<T, Action>();
protected EmployeeManagement empMgmnt = new EmployeeManagement();
public void InitializeHandler(int employeeID)
{
this.AddHandler(EmployeeRequests.BasicDetails, () => empMgmnt.GetEmployeeBasicDetails(0));
}
public void AddHandler(T caseValue, Action action)
{
handlers.Add(caseValue, action);
}
public void RemoveHandler(T caseValue)
{
handlers.Remove(caseValue);
}
public void ExecuteHandler(T actualValue)
{
ExecuteHandler(actualValue, Enumerable.Empty<T>());
}
public void ExecuteHandler(T actualValue, IEnumerable<T> ensureExistence)
{
foreach(var val in ensureExistence)
if (!handlers.ContainsKey(val))
throw new InvalidOperationException("The case " + val.ToString() + " is not handled.");
handlers[actualValue]();
}
}
And this is my function that I am passing as a parameter:
public object GetEmployeeBasicDetails(int employeeID)
{
return new { First_Name = "Mark", Middle_Initial = "W.", Last_Name = "Rooney"};
}
I am getting this error:
Overloaded method has some invalid arguments.
UPDATE
This is how I manage to get around this:
public static class RequestHandler
{
public enum EmployeeRequests { BasicDetails = 0, DependentsAndEmergencyContacts = 1 , MedicalHistory = 2 }
private static Dictionary<EmployeeRequests, Func<object>> handlers = new Dictionary<EmployeeRequests, Func<object>>();
public static void InitializeHandler(int employeeID)
{
Func<object> EmpBasicDetails = delegate { return EmployeeManagement.GetEmployeeBasicDetails(0); };
AddHandler(EmployeeRequests.BasicDetails, EmpBasicDetails);
}
private static void AddHandler(EmployeeRequests caseValue, Func<object> empBasicAction)
{
handlers.Add(caseValue, empBasicAction);
}
public static void RemoveHandler(int caseValue)
{
var value = (EmployeeRequests)Enum.Parse(typeof(EmployeeRequests), caseValue.ToString());
handlers.Remove(value);
}
public static object ExecuteHandler(int actualValue)
{
var request = (EmployeeRequests)Enum.Parse(typeof(EmployeeRequests), actualValue.ToString());
return handlers[(EmployeeRequests)request]();
}
}
You cannot pass a value-returning method as an Action, because Action<T> must take a parameter T and return nothing (i.e. void).
You can work around this by passing a lambda that calls your method and ignores its output:
Action empBasicAction = () => GetEmployeeBasicDetails(0);

Need some help for planning class model

I want to declare some functions for tests. For example:
CountWords(string text)
ExistsWordInText(string text, string searchedWord)
CountOfWord(string text, string searchedWord)
Now I want to declare "testdefintions". These testdefinitions will be added to a collection and include a function and, depending on the function, different parameters.
A method will now execute all the tests from the testdefintions collection and the tests will return a result.
I want to add functions in the future without changing anything else.
At the moment I am at this point:
IFunction-interface
public interface IFunction
{
#region Methods
void Run();
#endregion
}
Any function
public class AttributeExistenceFunction : FunctionBase
{
public override void Run() {
// Do any test
throw new FormatException();
}
}
TestDefinition-Class
public class TestDefinition : ITestDefinition
{
#region Fields
public IFunction Function { get; set; }
#endregion
#region Constructor
public TestDefinition(IFunction function)
{
this.Function = function;
}
#endregion
#region Methods
public void Run(Uri site)
{
this.Function.Run();
}
#endregion
}
Has anybody an idea how to realize the dynamic paramters / results?
I started it out optimistic, but it turned out really ugly.
I'll post it anyways since it does the job after all.
You can easily add Func constructors to support Action and lose the VoidReturn hack.
public class Func
{
public readonly MethodInfo Method;
public readonly object Target;
#region Ctors
public static Func Get<TResult>(Func<TResult> func)
{
return new Func(func.Method, func.Target);
}
public static Func Get<T, TResult>(Func<T, TResult> func)
{
return new Func(func.Method, func.Target);
}
public static Func Get<T1, T2, TResult>(Func<T1, T2, TResult> func)
{
return new Func(func.Method, func.Target);
}
public static Func Get<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> func)
{
return new Func(func.Method, func.Target);
}
#endregion
private Func(MethodInfo method, object target)
{
this.Method = method;
this.Target = target;
}
public object Run(params object[] parameters)
{
return this.Method.Invoke(this.Target, parameters);
}
}
public class MyClass
{
public string Data { get; set; }
public int Add(int x, int y)
{
return x + y;
}
public bool IsZero(int i)
{
return i == 0;
}
public void Print(object msg)
{
Console.WriteLine(msg);
}
public bool ValidateData()
{
return string.IsNullOrEmpty(this.Data);
}
public void TestMethods()
{
var tests = new Dictionary<Func, object[][]>
{
{
Func.Get<int, int, int>(this.Add),
new[]
{
new object[] {2, 3},
new object[] {5, 0},
new object[] {10, -2}
}
},
{
Func.Get<int, bool>(this.IsZero),
new[]
{
new object[] {1},
new object[] {0},
new object[] {-1}
}
},
{
Func.Get<object, VoidReturn>(o =>
{
this.Print(o);
return VoidReturn.Blank;
}),
new[]
{
new object[] {"Msg1"},
new object[] {"Msg2"},
new object[] {"Msg3"}
}
},
{Func.Get(this.ValidateData), null}
};
foreach (var testFunc in tests)
{
Console.WriteLine("Testing method: " + testFunc.Key.Method.Name);
Console.WriteLine();
foreach (var parameters in testFunc.Value)
{
Console.WriteLine("Parameters: " + string.Join(", ", parameters));
var result = testFunc.Key.Run(parameters);
Console.WriteLine(result is VoidReturn ? "*void" : ("Returned: " + result));
Console.WriteLine();
}
Console.WriteLine("________________________________");
Console.WriteLine();
}
}
private enum VoidReturn
{
Blank
}
}

Categories

Resources