This has a game development project under itself, but it's really about coding and mapping data to other pieces of data. This is why I decided to post it here.
The format that I'm using for external inventory item data storage:
[ID:IT_FO_TROUT]
[Name:Trout]
[Description:A raw trout.]
[Value:10]
[3DModel:null]
[InventoryIcon:trout]
[Tag:Consumable]
[Tag:Food]
[Tag:Stackable]
[OnConsume:RestoreHealth(15)]
[OnConsume:RestoreFatigue(15)]
The question is concentrated upon the last 2 OnConsume properties. Basically, the two properties mean that when the item gets consumed, the consumer's health goes up by 15 points, and his fatigue does so as well. This, in the background, invokes 2 different methods:
void RestoreHealth(Character Subject, int Amount);
void RestoreFatigue(Character Subject, int Amount);
How would you go about mapping the methods to their in-file string counterparts? This is what I thought of:
Every time an item gets consumed, a list of strings (the events) gets passed to an Item event manager. The manager parses each string and calls the appropriate methods. Very easy to set up, and since this is not an operation that happens too often, the impact on performance might not be considerable (strings will also be tiny (max 10-15 characters) in size, and parsed in O(n) time).
Each inventory item (class) parses the string events once and only once, on initialization. Each string event gets mapped to its appropriate method via a dictionary. This is the most efficient method in terms of performance that I can think of, but it makes it extremely difficult to do other things:
All of the values in the dictionary would have to be delegates of the same kind. This means I cannot keep
a) RestoreHealth(int)
b) SummonMonster(Position, Count)
in the same dictionary, and would have to set a new data structure for each kind of callable method. This is a tremendous amount of work to do.
Some ways that came to mind, to improve both methods:
I could use some sort of temporary cache inside the Item event
manager, so that an item's OnConsume events don't get parsed
twice? I might hit the same issues as the ones I hit during 2)
though, as the cache would have to be a map<InventoryItem,List<delegate>>.
The hashtable data structure inside the .NET libraries allows
for any kind of object to be a key and/or value at any given time
(unlike the dictionary). I could use this and map string A to
delegate X, while also having mapped string B to delegate Y
inside the same structure. Any reasons why I should not do this? Can
you foresee any trouble that would be brought by this method?
I was also thinking about something in the ways of reflection, but I'm not exactly experienced when it comes to it. And I'm pretty sure parsing the string every time is faster.
EDIT
My final solution, with Alexey Raga's answer in mind. Using interfaces for each kind of event.
public interface IConsumeEvent
{
void ApplyConsumeEffects(BaseCharacter Consumer);
}
Sample implementer (particular event):
public class RestoreHealthEvent : IConsumeEvent
{
private int Amount = Amount;
public RestoreHealthEvent(int Amount)
{
this.Amount = Amount;
}
public void ApplyConsumeEffects(BaseCharacter Consumer)
{
Consumer.Stats.AlterStat(CharacterStats.CharStat.Health, Amount);
}
}
Inside the parser (the only place where we care about the event's particularities - because we're parsing the data files themselves):
RestoreHealthEvent ResHealthEv = new RestoreHealthEvent (Value);
NewItem.ConsumeEvents.Add (ResHealthEv );
When a character consumes an item:
foreach (IConsumeEvent ConsumeEvent in Item.ConsumeEvents)
{
//We're inside a parent method that's inside a parent BaseCharacter class; we're consuming an item right now.
ConsumeEvent.ApplyConsumeEffects(this);
}
Why not "map" them to "command" classes once-and-only-once instead?
For example,
[OnConsume:RestoreHealth(15)]
[OnConsume:RestoreFatigue(15)]
could be mapped to RestoreHealth and RestoreFatigue command classes that can be defined as:
public sealed class RestoreHealth : ICommand {
public int Value { get; set; }
//whatever else you need
}
public sealed class SummonMonster : ICommand {
public int Count {get; set; }
public Position Position { get; set; }
}
Consider commands as just wrappers for your parameters at this point ;) So instead of passing multiple parameters you always wrap them and pass only one.
It also gives a bit of semantics too.
Now you can map your inventory items to commands that need to be "sent" when each item is consumed.
You can implement a simple "bus" interface like:
public interface IBus {
void Send(ICommand command);
void Subscribe(object subscriber);
}
and now you just get an instance of IBus and call its Send method when appropriate.
By doing this you separate your "definition" (what needs to be done) and your logic (how to perform an action) concerns.
For the receiving and reacting part you implement the Subscribe method to interrogate the subscriber instance (again, once and only once) figuring out all its method which can "handle" commands.
You can come up with some IHandle<T> where T: ICommand interface in your handlers, or just find them by convention (any Handle method that accepts only one argument of ICommand and returns void), or whatever works for you.
It is basically the same part of "delegate/action" lists that you were talking about except that now it is per command:
map<CommandType, List<action>>
Because all the actions now accept only one parameter (which is ICommand) you can easily keep them all in the same list.
When some command is received, your IBus implementation just gets the list of actions for the given command type and simply calls these actions passing the given command as a parameter.
Hope it helps.
Advanced: you can do one step further: have a ConsumeItem command:
public sealed void ConsumeItem: ICommand {
public InventoryItem Item { get; set; }
}
You already have a class that is responsible for holding a map between InventoryItem and Commands, so this class can become a process manager:
It subscribes to ConsumeItem command (through the bus)
In its Handle method it gets the list of commands for the given inventory item
It sends these commands to the bus.
Well, now we have separated clearly these three concerns:
While consuming an inventory item we just "know" about IBus and send a ConsumeItem command and we don't care what happens next.
The "ConsumeInventoryManager" (whatever you call it) also knows about IBus', subscribes forConsumeItem` command and "knows" what needs to be done when each item is consumed (list of commands). It just sends these commands and doesn't care who and how handle them.
The business logic (characters, monsters, etc) just handle the commands that make sense to them (RestoreHealth, Die, etc) and don't care where (and why) they came from.
Good luck :)
My advice is to use reflection, that is define a method that invokes the desired method based on the specified name. Here's a working example:
class Program
{
static void Main(string[] args)
{
SomeClass someInstance = new SomeClass();
string name = Console.ReadLine();
someInstance.Call("SayHello", name);
}
}
class SomeClass
{
public void SayHello(string name)
{
Console.WriteLine(String.Format("Hello, {0}!", name));
}
public void Call(string methodName, params object[] args)
{
this.GetType().GetMethod(methodName).Invoke(this, args);
}
}
You can do it this way provided the following conditions hold:
You are absolutely sure that a call is possible, that is a method of the specified name exists and the number and types of parameters are correct
The method of the specified name is not overloaded, otherwise You'll get a System.Reflection.AmbiguousMatchException
There exists a superclass from which all of the classes You want to use the Call method on derive; You should define this method in that class
To assure* that conditions 1. and 2. are satisfied You could use a more specific version of Type.GetMethod which takes into account not only the name of the method, but also the number and types of the parameters, and check that there is such a method before invoking it; then the Call method would look like this (*it won't work for methods with parameters marked as out or ref):
public void Call(string methodName, params object[] args)
{
//get the method with the specified name and parameter list
Type[] argTypes = args.Select(arg => arg.GetType()).ToArray();
MethodInfo method = this.GetType().GetMethod(methodName, argTypes);
//check if the method exists and invoke it
if (method != null)
method.Invoke(this, args);
}
REMARK: MethodInfo.Invoke method actually returns an object, so You could define the Call method to return some value by specifying the return type and using the return keyword together with an appropriate cast or some other method of converting the result to the desired type, if it's possible - remember to check if it is.
If condition 3. isn't satisfied, I'd go with writing an extension method. Here's an example of an extension method that returns a generic value, which I think should be sufficient in most cases (again, it won't work with ref or out) and should work on almost every object possible in the .NET Framework (I'd be grateful for pointing out a counterexample):
public static class Extensions
{
//invoke a method with the specified name and parameter list
// and return a result of type T
public static T Call<T>(this object subject, string methodName, params object[] args)
{
//get the method with the specified name and parameter list
Type[] argTypes = args.Select(arg => arg.GetType()).ToArray();
MethodInfo method = subject.GetType().GetMethod(methodName, argTypes);
//check if the method exists
if (method == null)
return default(T); //or throw an exception
//invoke the method and get the result
object result = method.Invoke(subject, args);
//check if something was returned
if (result == null)
return default(T); //or throw an exception
//check if the result is of the expected type (or derives from it)
if (result.GetType().Equals(typeof(T)) || result.GetType().IsSubclassOf(typeof(T)))
return (T)result;
else
return default(T); //or throw an exception
}
//invoke a void method more conveniently
public static void Call(this object subject, string methodName, params object[] args)
{
//invoke Call<object> method and ignore the result
subject.Call<object>(methodName, args);
}
}
You should then be able to use, for example, someObject.Call<string>("ToString") instead of someObject.ToString(). Finally, at this point I'd strongly recommend:
Use more specific type than object if possible
Use some more sophisticated and unique name than Call - it may get obscured in case some class has a method with the same signature defined
Lookup covariance and contravariance to get more useful knowledge
Related
I have this code (its just part, entire code works just fine):
internal static Rule<IWorkflowModel> Get()
{
var rule = new Rule<IWorkflowModel>("Argument Naming Rule", RuleId, Inspect)
{
DefaultErrorLevel = System.Diagnostics.TraceLevel.Warning,
RecommendationMessage = Recommendation
};
return rule;
}
private static InspectionResult Inspect(IWorkflowModel workflowModel, Rule ruleInstance)
{
I am trying to understand, how can we pass Inspect static method as parameter in line 3, without adding parameters to itself (like Inspect(paramA, paramB)?
I can guess it takes both Rule and IWorkflowModel objects from the rule created itself (line 3). But trying to figure out some logic/rule behind it.
Edit
This is Rule<T> class from metadata
namespace UiPath.Studio.Activities.Api.Analyzer.Rules
{
public sealed class Rule<T> : Rule where T : IInspectionObject
{
public Rule(string ruleName, string ruleId, Func<T, Rule, InspectionResult> inspectionFunction);
public Func<T, Rule, InspectionResult> Inspect { get; }
}
}
You're passing the function, not invoking it. This allows a different piece of code to invoke the function later, supplying the arguments.
The way this is done in C# is through delegates (since about .NET 3.5, instead of using custom delegate types, you will probably want to use Action and Func respectively). You can think of a delegate as a single-method interface - it's basically a bridge between object-oriented and true functional programming.
In older code, this was mainly used in events and callbacks. Today, as C# gets more and more functional, it's getting rather common for abstract functions to accept functions as arguments; LINQ was probably the first big example. You supply your own behaviour to other functions. You want to filter a collection? Just pass a function that does the filtering (col.Where(i => i.Name.Length > 3)).
To show you a possible way of implementing what you're seeing in your code:
public class Rule<T> : Rule
{
private readonly Func<T, Rule, InspectionResult> _inspect;
public Rule(string name, string ruleId, Func<T, Rule, InspectionResult> inspect)
: base(name, ruleId)
{
_inspect = inspect;
}
public InspectionResult Inspect(T model) => _inspect(this, model);
}
Note that when Rule<T> calls the delegate, it must supply all of the arguments.
Of course, the actual behaviour of the caller can be essentially arbitrary. The point is that you're passing a behaviour to someone else. Delegates are a very simple and quick way of doing that, especially combined with anonymous functions and all that.
I'm working with a project for thesis-work for a company and I'm having some difficulties understanding some code.
In their code they have a line like this
_subscriber.StartSubscribing(_messageHandler.HandleMessage);
where _subscriber is function is defined
public override void StartSubscribing(Action<QueueItem> messageHandlerMethod);
And _messageHandler is defined
public void HandleMessage(QueueItem message)
{
//Do code here
}
How come at the top the messageHandler don't need a parameter for HandleMessage?
E.I
_subscriber.StartSubscribing(_messageHandler.HandleMessage(QueueItem));
Because you're not actually executing the method HandleMessage (which would happen if you had parentheses and a parameter). You are passing it as a reference to StartSubscribing which expects a method with a specified signature (void return, one parameter of type QueueItem)
Action<T> is a generic delegate, this particular version is a delegate which specifies no return (void) and a single parameter of type T (or QueueItem in your example)
In fact, it is the method StartSubscribing (or perhaps the class it belongs to) which is likely to provide the instance of QueueItem - perhaps something like this:
public override void StartSubscribing(Action<QueueItem> messageHandlerMethod)
{
// do something to get/create a QueueItem
QueueItem item = SomeMagic();
// pass it back to the passed in delegate
messageHandlerMethod(item);
}
With _subscriber.StartSubscribing(_messageHandler.HandleMessage) you are using a more direct way for _subscriber.StartSubscribing(msg => _messageHandler.HandleMessage(msg)).
So it does need a parameter.
I have a number of 'jobs' in my application, where each job has a list of methods which it needs to call, along with it's parameters. Essentially a list containing the following object is called:
string Name;
List<object> Parameters;
So basically, when a job runs I want to enumerate through this list, and call the relevant methods. For example, if I have a method like the following:
TestMethod(string param1, int param2)
My method object would be like this:
Name = TestMethod
Parameters = "astring", 3
Is it possible to do this? I imagine reflection will be the key here.
Sure, you can do it like this:
public class Test
{
public void Hello(string s) { Console.WriteLine("hello " + s); }
}
...
{
Test t = new Test();
typeof(Test).GetMethod("Hello").Invoke(t, new[] { "world" });
// alternative if you don't know the type of the object:
t.GetType().GetMethod("Hello").Invoke(t, new[] { "world" });
}
The second parameter of Invoke() is an array of Object containing all the parameters to pass to your method.
Assuming the methods all belong to the same class, you could have a method of that class something like:
public void InvokeMethod(string methodName, List<object> args)
{
GetType().GetMethod(methodName).Invoke(this, args.ToArray());
}
If you're using .NET Framework 4, look at dynamic, otherwise GetMethod and then call Invoke of MethodInfo.
Use MethodBase.Invoke(). Should work down to .NET 2.0 with System.Reflection.
If you're using having to resort to reflection, there is probably a better way to accomplish your task. It may take a little more architecture, but it's doable.
Remember, having more code isn't a bad thing -- especially when it compliments the readability and manageability of your code. Reflection is difficult to understand for most, and you lose most of your compile time type safety. In your example, you could probably just get away with a switch statement and distinct objects for each method you were planning to call. e.g.
// Have some object hold the type of method it plans on calling.
enum methodNames
{
Method1,
Method2
}
...
class someObject
{
internal methodNames methodName {get; set;}
internal object[] myParams;
}
...
// Execute your object based on the enumeration value it references.
switch(someObject1.methodName)
{
case Method1:
Test.Method1(Int32.Parse(someObject1.myParams[0].ToString),someObject1.myParams[1].ToString());
break;
...
}
If you know that you only have a distinct set of method possibilities to call, why not just set yourself up ahead of time?
NuGet to the rescue! PM> Install-Package dnpextensions
Once you have that package in your project, all objects should now have a .InvokeMethod() extension, that will take the method name as a string and any number of parameters.
That does technically use "magic strings" for the method names, so if you wanted to strongly-type your method dictionary, you could make the keys of type MethodInfo and get them like this...
MethodInfo[] methodInfos = typeof(MyClass).GetMethods();
And then you can do something like this...
var methods = new Dictionary<MethodInfo, Object[]>();
foreach (var item in methods)
item.key.Invoke(null, item.value);
// 'null' may need to be an instance of the object that
// you are calling methods on if these are not static methods.
Or you could do some variation of the above block using the dnpextensions I mentioned earlier.
I have the following method with an overload:
public string GetName(object obj)
{
return obj.ToString();
}
public string GetName(CustomClass cc)
{
return cc.Name + " - " + cc.Description;
}
Now if I call the method with an untyped IEnumerable wich holds CustomClass the GetName(object obj) gets called, to fix this I have modified the method like this:
public string GetName(object obj)
{
if (obj is CustomClass)
return GetName(obj as CustomClass);
return obj.ToString();
}
I think its rather annoying to write 20 IF statements and catch all the other possibilities, is there an easier way to call the correct overload with an untyped IEnumerable enumeration?
Here is the code that calls the GetName(object obj):
IEnumerable rawData = GetData(); //DataBase method that fetches a CustomClass
foreach (var rawDataItem in rawData)
{
Debug.Print(GetName(rawDataItem)); //calls the GetName(object obj) overload
}
Pls dont tell me to override ToString from my CustomClass, help me fix this method calling problem.
Well, you could use dynamic typing. That will basically defer overload resolution until execution time:
foreach (dynamic rawDataItem in rawData)
{
Debug.Print(GetName(rawDataItem));
}
Note that there's potentially a performance cost here - it may well be minimal and insignificant, but it's worth being aware of.
EDIT: To handle the recursion side of things, you'd probably want two different names, e.g. GetName and GetNameImpl where GetName delegates to GetNameImpl which is what all the useful overloads are called. So you'd have:
// Note that dynamic as a parameter type is equivalent to object for callers.
// The dynamic part is only relevant within the method.
public string GetName(dynamic obj)
{
return GetNameImpl(obj);
}
// Fallback when no other overloads match
private string GetNameImpl(object obj)
{
...
}
private string GetNameImpl(IEnumerable obj)
{
// Maybe build up the name by calling GetName on each element?
}
Note that there's a potential problem with this: if you have two overloads for different interfaces and one type implements both interfaces (but there isn't a specific overload for that type itself) then you'll get an exception at execution time.
If you want callers to be able to call the overloads directly, you could just rename the dynamic one to GetNameDynamic and the others to GetName for example (and make them public).
I rarely find that dynamic is a good solution, but it would avoid the code duplication. I would try to step back and find a different design to be honest. You explicitly rejected it in the question, but polymorphism is the preferred way of handling this. You don't need to necessarily override ToString - you could make all of the custom types implement a particular interface, and use that where it's available, for example.
return GetName((dynamic)obj);
will postpone overload resolution till runtime.
Without dynamic typing, the classic OOP solution to supporting double dispatch (where the method called depends on both the concrete type of the object having the method and the concrete type of the passed object) is the visitor pattern.
Try this:
public string GetName(object obj)
{
if (!(obj is IEnumerable<object>))
return GetName(obj as CustomClass);
return obj.ToString();
}
I want to have a library that will have a function in it that accepts an object for it's parameter.
With this object I want to be able to call a specified function when X is finished. The function that will be called is to be specified by the caller, and X will be done and monitored by the library.
How can I do this?
For reference I'm using C# and .NET 3.5
Two options for you:
Have the function accept a delegate (Action for a callback that doesn't return anything, Func for one that does) and use an anonymous delegate or Lambda Expression when calling it.
Use an interface
Using a delegate/lambda
public static void DoWork(Action processAction)
{
// do work
if (processAction != null)
processAction();
}
public static void Main()
{
// using anonymous delegate
DoWork(delegate() { Console.WriteLine("Completed"); });
// using Lambda
DoWork(() => Console.WriteLine("Completed"));
}
If your callback needs to have something passed to it, you can use a type parameter on Action:
public static void DoWork(Action<string> processAction)
{
// do work
if (processAction != null)
processAction("this is the string");
}
public static void Main()
{
// using anonymous delegate
DoWork(delegate(string str) { Console.WriteLine(str); });
// using Lambda
DoWork((str) => Console.WriteLine(str));
}
If it needs multiple arguments, you can add more type parameters to Action. If you need a return type, as mentioned use Func and make the return type the last type parameter (Func<string, int> is a function accepting a string and returning an int.)
More about delegates here.
Using an interface
public interface IObjectWithX
{
void X();
}
public class MyObjectWithX : IObjectWithX
{
public void X()
{
// do something
}
}
public class ActionClass
{
public static void DoWork(IObjectWithX handlerObject)
{
// do work
handlerObject.X();
}
}
public static void Main()
{
var obj = new MyObjectWithX()
ActionClass.DoWork(obj);
}
Sounds like a perfect recipe for delegates - in particular, callbacks with delegates are exactly how this is handled in the asynchronous pattern in .NET.
The caller would usually pass you some state and a delegate, and you store both of them in whatever context you've got, then call the delegate passing it the state and whatever result you might have.
You could either make the state just object or potentially use a generic delegate and take state of the appropriate type, e.g.
public delegate void Callback<T>(T state, OperationResult result)
Then:
public void DoSomeOperation(int otherParameterForWhateverReason,
Callback<T> callback, T state)
As you're using .NET 3.5 you might want to use the existing Func<...> and Action<...>
delegate types, but you may find it makes it clearer to declare your own. (The name may make it clearer what you're using it for.)
The object in question will need to implement an interface provided by you. Take the interface as a parameter, and then you can call any method that the interface exposes. Otherwise you have no way of knowing what the object is capable of. That, or you could take a delegate as a parameter and call that.
Is there a reason not to have your library provide a public event to be fired when the operation is complete? Then the caller could just register to handle the event and you don't have to worry about passing around objects or delegates.
The object implementing an interface you have provided would work, but it seems to be more the Java approach than the .NET approach. Events seem a bit cleaner to me.
You can use System.Action available in C#.NET for callback functions. Please check this sample example:
//Say you are calling some FUNC1 that has the tight while loop and you need to
//get updates on what percentage the updates have been done.
private void ExecuteUpdates()
{
Func1(Info => { lblUpdInfo.Text = Info; });
}
//Now Func1 would keep calling back the Action specified in the argument
//This System.Action can be returned for any type by passing the Type as the template.
//This example is returning string.
private void Func1(System.Action<string> UpdateInfo)
{
int nCount = 0;
while (nCount < 100)
{
nCount++;
if (UpdateInfo != null) UpdateInfo("Counter: " + nCount.ToString());
//System.Threading.Thread.Sleep(1000);
}
}