Pattern to reuse logic regardless of number of parms - c#

I have some logging logic I want to call before and after several methods. Each method accepts different number/type of parameters. I'm trying to set it up so I don't have to duplicate the logging logic when I call each method. I've been able to reduce the amount of duplication by creating some delegates. I've created a delegate for each number/type of parms used and I have a method that accepts each delegate and does the logging. However, I still have around 6 different delegates and so the logic is duplicated for those six.
I think there is away to modify this so regardless of the number of parms, I have one method that does the logging and calls the method. But I haven't been able to figure it out.
Below is an example of one of the delegates and the logic I'm trying not to duplicate.
public delegate void LineOfBusinessHandler(DateTime runDate, LineOfBusinessCode lineOfBusinessCode);
public void Run(DateTime runDate, ProcessCode process, LineOfBusinessCode lineOfBusinessCode, LineOfBusinessHandler del)
{
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Started.ToString(), null, runDate);
try
{
del(runDate, lineOfBusinessCode);
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Finished.ToString(), null, runDate);
}
catch (Exception e)
{
int errorId = SystemManager.LogError(e, process.ToString());
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Errored.ToString(), errorId, runDate);
}
}

I realize this maybe beyond the scope and/or the capabilities of what you're looking for. But if you have a generic logging logic that you want to reuse over different method calls, without losing typesafety (i.e. NOT passing your arguments around in object[]) the way to go is interception. You need a framework (I don't recommend writing your own at first!) that can provide AOP, Dependency Injection or something similiar. Those things can usually deal with interception.
For example I have a logging interceptor I use with Ninject:
public void Intercept(IInvocation invocation)
{
var logger = LoggerFactory.GetLogger(invocation.Request.Method.DeclaringType);
var debug = !invocation.Request.Method.IsSpecialName && logger.IsDebugEnabled;
if (debug)
logger.Debug(invocation.Request.Method.Name);
try
{
invocation.Proceed();
if (debug)
logger.Debug(invocation.Request.Method.Name + " FINISH");
}
catch (Exception)
{
logger.Error(invocation.Request.Method.Name + " ERROR");
throw;
}
}
Then I create my objects by getting them with Ninject (if you don't know about it, check out some tutorials), while adding some Interception to them, for example: Kernel.Bind<MyTypeToLog>().ToSelf().Intercept().With<LoggingInterceptor>(); where LoggingInterceptor implements IInterceptor with the method shown above...
Just say if you need more in details help!
EDIT: just realized that my example doesn't show this, but you can access the arguments (as an object collection though) of the invocation too!!

It depends on what is common among the different versions, but assuming runDate and process are common you could do something like this:
public void Run(DateTime runDate, ProcessCode process, LineOfBusinessCode lineOfBusinessCode, LineOfBusinessHandler del)
{
this.DoRun(runDate, process, (d, p) => del(d, p, lineOfBusinessCode));
}
public void DoRun(DateTime runDate, ProcessCode process, Action<DateTime, ProcessCode> action)
{
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Started.ToString(), null, runDate);
try
{
action(runDate, process);
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Finished.ToString(), null, runDate);
}
catch (Exception e)
{
int errorId = SystemManager.LogError(e, process.ToString());
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Errored.ToString(), errorId, runDate);
}
}
You can even generalize so you don't have do define custom delegates as this:
public void Run<T1>(DateTime runDate, ProcessCode process, T1 param1, Action<DateTime, ProcessCode, T1> del)
{
this.DoRun(runDate, process, (d, p) => del(d, p, param1));
}
public void Run<T1, T2>(DateTime runDate, ProcessCode process, T1 param1, T2 param2, Action<DateTime, ProcessCode, T1, T2> del)
{
this.DoRun(runDate, process, (d, p) => del(d, p, param1, param2));
}

The C# language doesn't have any syntax for metaprogramming. You'll have to use reflection. You certainly can reflect against an arbitrary method/delegate to determine the parameter types, then build a method that logs parameters and calls the original method, compile this new wrapper method, and return a delegate with the same call signature as the original.
You can do this at runtime (return a delegate) or build a new assembly with all the wrapper functions, that can then be referenced by your code and used normally.
You should look at the code-weaving tools used for Aspect-Oriented-Programming. Some of them already do this.
Unlike using a params array, this gives you a wrapper with the same signature (or delegate type) as the original method, so it is type safe and Intellisense works (as much as for any other delegate).

If I understand your question correctly it sounds like you could use the C# params keyword. See this for a reference on how to use it: http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
One of the requirements when using params is that it has to be placed last in the signature of the function. Then, inside of the function you can enumerate and iterate over the variable parameters list as if it were an array.
EDIT
To expand on a comment posted by #Ben Voigt, another limitation of using the params keyword is that it requires the variable parameter list to be of the same type. This however can be mitigated in your case since all you care about is logging. In this case presumably you would be invoking the ToString() method on the objects you need to log so you could make the variable parameters list of type object.
In case calling the ToString() is not enough and you have different types of objects you could make all these objects implement a common interface. Let's call it ILoggableObject which exposes a method to provide the logging output. That's if you have the ability to change those objects.

Related

C# Generic Method vs Casting

I'm writing a program in C# (3.5 at the moment, but likely to be adaptable to other versions as the need arises) that uses a simple plugin architecture to control input and output. Each plugin is a DLL that is loaded when the user chooses the plugins to use.
Since the actual plugin class isn't known until run time, I'm using reflection in a wrapper class to call methods and access properties of the plugins.
Up until now, I've been using the following to call methods on a plugin:
public object Method(string methodName, params object[] arguments) {
// Assumed variables/methods/exceptions:
// Dictionary<string, MethodInfo> Methods: a cache of MethodInfo's
// of previously called methods.
// NoSuchMethodException: thrown if an unknown/unreachable method is
// requested. The message member contains the invalid method name
// void LoadMethod(string methodName, params object[] arguments): responsible
// for retrieving the MethodInfo's, or throw a NoSuchMethodException
// object Plugin: an instance of the dynamically loaded class.
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
return Methods[methodName].Invoke(Plugin, arguments);
}
Which is used like:
string[] headers = (string[]) Plugin.Method("GetHeaders", dbName, tableName);
This works nicely, as long as the caller correctly casts the return value to the expected
type. Plugins must implement certain interfaces, so the caller should know this type.
After doing some further work with reflection however, the following alternate form occurred to me:
public T Method<T>(string methodName, params object[] arguments) {
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (Methods[methodName].ReturnType != typeof(T)) {
// Could also move this into LoadMethod to keep all the throwing in one place
throw new NoSuchMethodException(methodName);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
return (T) Methods[methodName].Invoke(Plugin, arguments);
}
This one is used like:
string[] headers = Plugin.Method<string[]>("GetHeaders", dbName, tableName);
This version essentially moves the casting into the Method method. The caller obviously still needs to know the expected return type, but that was always going to be the case. It doesn't work for void methods, but I can include a version of Method for that:
public void Method(string methodName, params object[] arguments) {
// Good for void methods, or when you're going to throw away the return
// value anyway.
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
Methods[methodName].Invoke(Plugin, arguments);
}
My question is - is one of these intrinsically better than the other (for a given value of 'better')? For instance, is one notably faster? Easier to understand? More supported?
I personally like the look of the latter, although I am a bit worried that my return type testing (Methods[methodName].ReturnType != typeof(T)) might be too simplistic. Interestingly, it was originally !(Methods[methodName].ReturnType is T), but that always seemed to fail.
The closest existing question to this I could find was Generic method to type casting, and some of the answers suggested that the latter method is more expensive than the former, but there's not much in the way of detail there (the question there is more towards implementation of the method rather than which is better).
Clarification: This is a hand-rolled, very limited plugin system, not using IPlugin. I'm more interested in the question of whether generic methods are inherently better/worse than expecting the caller to cast in this situation.
As to your question I think you should provide both. Simply have the generic version invoke the non-generic version. You get the best of both worlds. Regarding performance, consider how small the time it takes to cast an object is in comparison to dynamically invoking a method and building up and object array. It really is not worth taking performance into consideration here. I for one prefer the generic approach from a stylistic perspective but also consider that you could apply type constraints should the need arise.
public T Method<T>(string methodName, params object[] arguments)
{
return (T)Method(methodName, arguments);
}
Side Bar
I'm thinking that your implementation should be casting to the expected interface if I understand your design. You really should not be using reflection if you know what methods the plugins should support.
var plugin = (IPlugin)Activator.CreateInstance(pluginType);
var headers = plugin.GetHeaders(dbName, tableName);
You could try something a bit different and require the plugin to implement an interface that allows them to register custom runtime behavior.
public interface IPlugin
{
void Load(IAppContext context);
void Unload();
}
Your loading method could look like this.
void LoadPlugins(Assembly a)
{
var plugins =
a.GetTypes()
.Where(t => typeof(IPlugin).IsAssignableFrom(t))
.Select(t => (IPlugin)Activator.CreateInstance(t))
.ToList();
Plugins.AddRange(plugins);
foreach (var p in plugins)
{
p.Load(Context);
}
}

How to replace lambda delegate

(removed unnecessary clutter)
Edit 1
Seems that my questions are not very clear... doh... :)
So ....
How to write this:
instance.Method(e => OtherClass.Fill(e, instance2.A, instance3.B));
with something like this:
instance.Method(new Action<IDataReader>(OtherClass.Fill));
When "Method" signature is:
void Method(Action<IDataReader> reader)
and "Fill" signature is:
void Fill(IDataReader reader, string a, string b);
Update
I figured out one alternative implementation, but it still causes debugger to step in to that Fill call. There's no anymore lambda notation but it still seems to step in, argh...
instance.Method(delegate(IDataReader e) { OtherClass.Fill(e, instance2.A, instance3.B); });
Solution
Seems that I just need one additional method which is called from delegate and that method then passes call to next method (Fill) with two more parameters:
instance.Method(this.Foo);
[DebuggerStepThrough()]
private void Foo(IDataReader reader)
{
OtherClass.Fill(reader, this.instance2.A, this.instance3.B)
}
The thing is, somewhere your code must pass those extra parameters, and your debugging experience will walk over that process. The best I can offer you is to wrap the parameter passing a little.
Either:
Action<IDataReader> wrapper = reader => this.Fill(reader, instance2.A, instance3.B);
instance.Method(wrapper);
or:
Func<Action<IDataReader, string, string>, Action<IDataReader>> reducer = arity3 => reader => arity3(reader, instance2.A, instance3.B);
instance.Method(reducer(this.Fill));
But obviously, either solution is still going to have the debugger 'walk' over the code. You can't pass parameters without actually passing the parameters.

Easiest way to create a delegate when the method contains a 'ref' parameter

Let's say I have this method:
public static object CallMethod(Delegate method, params object[] args)
{
//more logic
return method.DynamicInvoke(args);
}
This below has worked fine for most scenarios, calling it like so (simple example):
Delegate methodCall = new Func<decimal,decimal>(Math.Ceiling);
object callResult = CallMethod(methodCall, myNumber);
However, I've run into a situation where I need to use this on a method that takes in a 'ref' parameter (WCF service call), which the Func class can not handle.
Delegate methodCall =
new Func<MyService.InputClass, MyService.CallResult>(service.DoWork);
Since I don't have a lot of experience dealing with delegates, what would be the easiest way of creating a delegate for the above method to pass on to mine?
This isn't my application so I don't have an easy way of testing it (I was just asked if I knew of a way of resolving the problem), but does this look like it should work?
Delegate methodCall = new Func<MyService.CallResult>(delegate() { return service.DoWork(ref myInput)});
object callResult = CallMethod(methodCall, null);

What is the most appropriate way to handle corrupt input data in a C# constructor?

I'm reading data in from a file and creating objects based on this data. The data format is not under my control and is occasionally corrupt. What is the most appropriate way of handling these errors when constructing the objects in C#?
In other programming languages I have returned a null, but that does not appear to be an option with C#.
I've managed to figure out the following options, but I would appreciate advice from more experienced C# programmers:
Option 1. Read the file inside the constructor and throw an exception when the source data is corrupt:
try
{
obj = Constructor(sourceFile);
... process object ...
}
catch (IOException ex)
{
...
}
Option 2. Create the object, then use a method to read data from the source file:
obj = Constructor();
obj.ReadData(sourceFile);
if (obj.IsValid)
{
... process object ...
}
or possibly throw exceptions on error:
obj = Constructor();
try
{
obj.Read(sourceFile);
... process object ...
}
catch
{
...
}
Option 3. Create the object using a static TryParse method:
if (ObjClass.TryParse(sourceFile, out obj))
{
... process object ...
}
and if so, should I implement option 3 internally using option 1?
public static bool TryParse(FileStream sourceFile, out ObjClass obj)
{
try
{
obj = Constructor(sourceFile);
return true;
}
catch (IOException ex)
return false;
}
I would do something along the lines of option 3):
class ObjectClass
{
protected ObjectClass(...constructor parameters your object depends on...)
{
}
public static ObjectClass CreateFromFile(FileStream sourceFile)
{
.. parse source file
if (parseOk)
{
return new ObjectClass(my, constructor, parameters);
}
return null;
}
}
And then use it like this:
ObjClass.CreateFromFile(sourcefile);
In general the constructor should take as parameters all properties which essentially define the class. Doing heavyweight calculations (like parsing a file) is best left to factory methods as it is usually not expected for the constructor to perform complex and potentially long running tasks.
Update: As mentioned in comments a better pattern is this:
public static ObjectClass CreateFromFile(FileStream sourceFile)
{
.. parse source file
if (!parseOk)
{
throw new ParseException(parseErrorDescription);
}
return new ObjectClass(my, constructor, parameters);
}
public static bool TryCreateFromFile(FileStream sourceFile, out ObjectClass obj)
{
obj = null;
.. parse source file
if (!parseOk)
{
return false;
}
obj = new ObjectClass(my, constructor, parameters);
return true;
}
I would not put anything into a constructor that might throw an exception - except for if something goes really wrong.
If your constructor has a possible return value other than a valid object, you should encapsulate it.
The safest way would probably be to create a factory method (public static function in the class that accepts a file reference and returns a new instance of the class or null). This method should first validate the file and its data and only then create a new object.
If the file data has a simple structure, you can first load it into some local variable and construct the object with this data.
Otherwise, you can still decide - inside of your factory method - if you rather want to try / catch the construction or use any of the other points mentioned above.
Both Options #1 and #3 are good choices and common in the .Net framework. It's also common to provide both for the same type. Consider Int32.TryParse and Int32.Parse. Providing both gives developers a bit more flexibility without detracting from the integrity of the type.
I would strongly advise you to avoid #2. This pattern forces both the type author and type consumer to handle instances of the type in multiple states
Constructed but not fully initialized
Initialized and valid
Initialized and invalid
This puts a burden on every consumer to deal with instances being in all different states (even if the response is to just throw). Additionally it forces a non-standard pattern on consumers. Developers have to understand your type is special and that it needs to be constructed and then initialized. It goes against the standard way objects are created in .Net.
Note for #3 though I would approach it a bit different. The exception form should be implemented in terms of the try form. This is the standard pattern when providing both options to the user. Consider the following pattern
class MyType {
struct ParsedData {
// Data from the file
}
public MyType(string filePath) : this(Parse(filePath)) {
// The Parse method will throw here if the data is invalid
}
private MyType(ParsedData data) {
// Operate on the valid data. This doesn't throw since the errors
// have been rooted out already in TryParseFile
}
public static bool TryParse(string filePath, out MyType obj) {
ParsedData data;
if (!TryParseFile(filePath, out data)) {
obj = null;
return false;
}
obj = new MyType(data);
return true;
}
private static ParsedData Parse(string filePath) {
ParsedData data;
if (!TryParseFile(filePath, out data)) {
throw new Exception(...);
}
return data;
}
private static bool TryParseFile(string filePath, out ParsedData data) {
// Parse the file and implement error detection logic here
}
}
From Microsoft Constructor Design Guidelines (MSDN),
Do throw exceptions from instance constructors if appropriate.
Constructors should throw and handle exceptions like any method. Specifically, a constructor should not catch and hide any exceptions that it cannot handle.
Factory Method is not the right way to approach this problem. See Constructors vs Factory Methods
From Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries
5.3 Constructor Design
Consider using a static factory method instead of a constructor if the
semantics of the desired operation do not map directly to the construction
of a new instance, or if following the constructor design guidelines
feels unnatural.
Do throw exceptions from instance constructors if appropriate.
.NET BCL implementations do throw exceptions from constructors
For example, the List Constructor (Int32), throws an ArgumentOutOfRangeException when the capacity argument of the list is negative.
var myList = new List<int>(-1); // throws ArgumentOutOfRangeException
Similarly, your constructor should throw an appropriate type of exception when it reads the file. For example, it could throw FileNotFoundException if the file does not exist at the specified location, etc.
More Information
Code Contracts
Throwing exceptions from constructor in .Net
Throwing ArgumentNullException in constructor?
Constructor parameter validation in C# - Best practices
All these solutions work, but as you said, C# doesn't allow to return null from a constructor. You either get an object or an exception. Since this is the C# way to go, I wouldn't choose option 3, because that merely mimics that other language you're talking about.
Lots of people [edit] among which is Martin, as I read in his answer :) [/edit] think it is good to keep your constructor clean and small. I'm not so sure about that. If your object is of no use without that data, you could read in the data in the constructor too. If you want to construct the object, set some options, and then read the data (especially with the possility to try again if the read fails), a separate method would be fine as well. So option 2 is a good possibility too. Even better maybe, depending mainly on taste.
So as long as you don't choose 3, choose the one you're the most comfortable with. :)

Is there a way to get an array of the arguments passed to a method?

Say I have a method:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
object[] args = GetArguments();
LogParamaters(args);
#endif
// Do Normal stuff in the method
}
Is there a way to retrieve an array of the arguments passed into the method, so that they can be logged?
I have a large number of methods and want to avoid manually passing the arguments by name to the logger, as human error will inevitably creep in.
I'm guessing it will involve reflection in some form - which is fine, as it will only be used for debugging purposes.
Update
A little more information:
I can't change the method signature of SomeMethod, as it is exposed as a WebMethod and has to replicate the legacy system it is impersonating.
The legacy system already logs the arguments that are passed in. To start with the new implementation will wrap the legacy system, so I'm looking to log the parameters coming into the C# version, so that I can verify the right parameters are passed in in the right order.
I'm just looking to log the argument values and order, not their names.
If you use Postsharp you can simply add an attribute to the method you want to log. Within this attribute you can write the logging code and also will provide the arguments you need. This is known as cross cutting concerns and AOP (Aspect orientated programming)
I am unsure if the API to access the call stack provides a means to get the argument list.
However there are ways to inject IL to intercept method calls and execute custom code.
The Library I use frequently is PostSharp by Gael Fraiteur, it includes an application that runs postbuild and injects IL in your output assemblies depending on the Aspects that you are using. There are attributes with which you can decorate assemblies, types, or individual methods. For instance:
[Serializable]
public sealed class LoggingAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs eventArgs)
{
Console.WriteLine("Entering {0} {1} {2}",
eventArgs.Method.ReflectedType.Name,
eventArgs.Method,
string.Join(", ", eventArgs.Arguments.ToArray()));
eventArgs.MethodExecutionTag = DateTime.Now.Ticks;
}
public override void OnExit(MethodExecutionArgs eventArgs)
{
long elapsedTicks = DateTime.Now.Ticks - (long) eventArgs.MethodExecutionTag;
TimeSpan ts = TimeSpan.FromTicks(elapsedTicks);
Console.WriteLine("Leaving {0} {1} after {2}ms",
eventArgs.Method.ReflectedType.Name,
eventArgs.Method,
ts.TotalMilliseconds);
}
}
After this you can just decorate the method you want with this Attribute:
[Logging]
public void SomeMethod(String p1, String p2, int p3)
{
//..
}
Well, if you just want to pass the values, you can cheat and define an object array:
public static void LogParameters(params object[] vals)
{
}
This will incur boxing on value types and also not give you any parameter names, however.
Say I have a method:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
LogParamaters(p1, p2, p3);
#endif
// Do Normal stuff in the method
}
Update: unfortunately reflection will not do it all automatically for you. You will need to provide the values, but you can use reflection to provide the param names/types:
How can you get the names of method parameters?
So the method sig would change to something like:
public static void LogParameters(string[] methodNames, params object[] vals)
{ }
Then you can enforce/assume that each index in each collection tallies, such that methodNames[0] has the value vals[0].
Well params help with the log call, but won't help the existing method signatures. Logging using an AOP framework might be a more productive approach?
Sure can ...check out this post, it gets the actual values of the params.
how to enumerate passed method parameters
There's some functionality with the dynamic type system that can do it, but then your class needs to inherit from the dynamic base classes
might not work in some scenarios but should get you started :)
class Program
{
static void Main(string[] args)
{
M1("test");
M2("test", "test2");
M3("test", "test2", 1);
Console.ReadKey();
}
static void M1(string p1)
{
Log(MethodBase.GetCurrentMethod());
}
static void M2(string p1, string p2)
{
Log(MethodBase.GetCurrentMethod());
}
static void M3(string p1, string p2, int p3)
{
Log(MethodBase.GetCurrentMethod());
}
static void Log(MethodBase method)
{
Console.WriteLine("Method: {0}", method.Name);
foreach (ParameterInfo param in method.GetParameters())
{
Console.WriteLine("ParameterName: {0}, ParameterType: {1}", param.Name, param.ParameterType.Name);
}
}
}
As long as you know what types to expect you could log them in an SQL database. Write a method that does a type check, and then fills the appropriate DB column with the parameter (argument) value. If you have a custom type then you can use the type name and save that as string in it's own special column.
-Edit
Also, using the MethodBase.Name extension method, you could associate your parameters with the method that took them as arguments as mentioned in another post below. Be a handy way of keeping track of all methods used, and with which arguments, and of which type.
Is this even vaguely a good idea? :)
Here's what I came up with as a solution:
PostSharp or another AOP solution wasn't really practical in this situation, so unfortunately I had to abandon that idea.
It appears that while it is possible to parameter names and types using reflection, the only way to access the runtime values is with a debugger attached.
See here for more info:
StackOverflow
microsoft.public.dotnet.framework
So that still left me with the problem of ~50 methods that needed this logging adding by hand.
Reflection to the rescue...
public String GetMethodParameterArray()
{
var output = new StringBuilder();
output.AppendLine();
Type t = typeof(API);
foreach (var mi in t.GetMethods())
{
var argsLine = new StringBuilder();
bool isFirst = true;
argsLine.Append("object[] args = {");
var args = mi.GetParameters();
foreach (var pi in args)
{
if (isFirst)
{
isFirst = false;
}
else
{
argsLine.Append(", ");
}
argsLine.AppendFormat("{0}", pi.Name);
}
argsLine.AppendLine("};"); //close object[] initialiser
output.AppendLine(argsLine.ToString());
output.AppendFormat("Log(\"{0}\",args);", mi.Name);
output.AppendLine();
output.AppendLine();
}
return output.ToString();
}
This code snippet loops through the methods on a class and outputs an object[] array initialised with the arguments passed into the method and a Log call containing the arguments and the method name.
Example output:
object[] args = {username, password, name, startDate, endDate, cost};
Log("GetAwesomeData",args);
This block can then be pasted into the top of the method to achieve the required effect.
It is more manual than I would have liked, but it is a lot better than having to type the parameters by hand and far less error prone.

Categories