I have a class instance (Eli) which is used in multiple contexts, and which needs to log messages, independent of (but correctly in each) context:
public class Eli
{
void LogMessage(string msg)
{
///what to do here?
}
public void GrillTheCat()
{
LogMessage("I deed it";)
}
}
public class EliWrapper
{
Eli _eli;
Action<string> _logAction;
public EliWrapper(Eli eli, Action<string> logAction)
{
_eli = eli;
_logAction = logAction;
}
public void GrillTheCat()
{
_eli.GrillTheCat(); //I want LogMessage in Eli to invoke the _logAction of this calling instance
}
}
var eli = new Eli();
var wrapper1 = new EliWrapper(eli, msg => Console.WriteLine(msg));
var wrapper2 = new EliWrapper(eli, msg => File.AppendAllText(msg + "\n"));
I realize I could pass in the logger to the GrillTheCat function, but in my real situation, Eli has >10 functions and I don't want to clutter up all of the function signatures just for the sake of logging.
I also realize I could define a LogAction property on Eli, then have the wrappers assign their _logAction value to that property prior to invoking Eli's function, but again I have many functions and it would be somewhat tedious to wrap each one.
What I'm hoping for is a reflection-based solution where Eli's LogMessage function just steps up a couple layers of the call stack, and accesses the wrapper instance's _logAction directly.
What I'm hoping for is a reflection-based solution where Eli's LogMessage function just steps up a couple layers of the call stack, and accesses the wrapper instance's _logAction directly.
I wasn't able to find any reasonable way to access instances outside the current executing method without you heavily modifying signatures(you stated you didn't want to do).
Although I generally would not recommend what you're trying to do because of the tight coupling and general lack of extensibility and intuitiveness - However, I figured out a solution that almost fits the bill.
It is not possible, at least from what I was able to research, to access instance data from calling members. Which is to say you can't walk back up the stack and access instanced variables or objects all will-nilly, unless you explicitly capture and pass them down the stack as you're - err.. um "stacking"?.
The way we work around this is simply by declaring your _logAction as a static member. That way we don't need to access the instance you have of EliWrapper.
What this doesn't do for you is allow you to have multiple EliWrappers with different _logAction's becuase they're static.
Unfortunately without access to the individual instance(which you can't get from the stack - there's no way for Eli to know what EliWrapper wants to do without at least some of the modifications you explicitly wanted to avoid(In my opinion).
Where do we go from here?
Consider
Consider Modifying Eli so it can be used as a base-class that has different versions that log things differently.
Consider Modifying Eli to implement overrides that accept a Action<string> as a override for it's default logging.
Alternatively, but not recommended
Pass the instance of the caller to Eli so it can access instanced(non-static) members on EliWrapper so you don't need to make _logAction static(this would be a simple modification to the code i have provided to you, but would require changing all of Eli's signatures to accommodate object caller.
Store instances of EliWrapper somewhere you can access without instance, such as a static class, where you can access their instance data using reflection without explicitly passing their instances to Eli
Here's the script to access the static field using the stack
public class Eli
{
private readonly Action<string> DefaultLogger = (s) => Console.WriteLine(s);
void LogMessage(string msg)
{
// get the stack so we can get advanced information about
// who called us (CallerMemberNameAttribute was another alternative, but would incur more complex code)
StackTrace stack = new(false);
// step 2 frames up(or however many to get out of Eli and back to the 'caller'
var caller = stack.GetFrame(2)?.GetMethod()?.DeclaringType;
if (caller != null)
{
// check to see if the type that called GrillTheCat()
// has a static private field with the name '_logAction'
var possibleLoggerInCaller = caller.GetField("_logAction", BindingFlags.Static | BindingFlags.NonPublic);
if (possibleLoggerInCaller != null)
{
// get the static value of that field
var possibleLogger = possibleLoggerInCaller.GetValue(null);
// verify that the type of that logger is infact a Action<string>
// since that's what we use to log
if (possibleLogger is Action<string> logger)
{
// log the msg using the overriden logger instead of the default one
logger.Invoke(msg);
return;
}
}
}
// if we got here there wasn't a _logAction in the call stack at frame 2
// so give up and use our default logger
DefaultLogger.Invoke(msg);
}
public void GrillTheCat()
{
LogMessage("I deed it");
}
}
public class EliWrapper
{
Eli _eli;
private static Action<string> _logAction;
public EliWrapper(Eli eli, Action<string> logAction)
{
_eli = eli;
_logAction = logAction;
}
public void GrillTheCat()
{
_eli.GrillTheCat(); //I want LogMessage in Eli to invoke the _logAction of this calling instance
}
}
For my needs, I've gone with throwing exceptions. This procedurally does what I asked: only notifies the calling instance of the message, and requires no modification of function signatures.
Consider implementing a decorator for Eli that implements logging. Here is a rudimentary example that demonstrates this:
// If you haven't already: define an interface for Eli
public interface IEli
{
// Define all Eli's public members
}
// Let Eli implement IEli
public class Eli : IEli
{
...
}
With the existence of the new IEli interface, you can now implement a decorator:
public class LoggingEli : IEli
{
private readonly IEli decoratee;
private readonly Action<string> logAction;
public LoggingEli(IEli decoratee, Action<string> logAction)
{
this.decoratee = decoratee;
this.logAction = logAction;
}
// Implement all IEli members by calling the log action and forwarding
// the call to the decorated IEli instance:
public object SomeEliMethod(string param1, int param2)
{
this.logAction(nameof(SomeEliMethod) + " called for " + param1);
return this.decoratee.SomeEliMethod(param1, param2);
}
// Same for all other 9 IEli methods.
}
Using the new IEli interface and the LoggingEli decorator, you can now construct the following object graph:
var eli = new Eli();
var consoleEli = new LoggingEli(eli, msg => Console.WriteLine(msg));
var fileEli = new LoggingEli(eli, msg => File.AppendAllText(msg + "\n"));
Decorators have the advantage that you are able to add behavior to a class without having to change the original class. Downside is that it is only possible to add behavior at the start or end of the original method, and the behavior only has access to all the parameters going in and out of the called method. In your case, you can't log halfway the method, and can't log anything information that is kept internal to Eli.
In case you need to log halfway or use information that is internal to Eli, you will need to inject the logger into Eli's constructor.
Related
For a given class I would like to have tracing functionality i.e. I would like to log every method call (method signature and actual parameter values) and every method exit (just the method signature).
How do I accomplish this assuming that:
I don't want to use any 3rd party
AOP libraries for C#,
I don't want to add duplicate code to all the methods that I want to trace,
I don't want to change the public API of the class - users of the class should be able to call all the methods in exactly the same way.
To make the question more concrete let's assume there are 3 classes:
public class Caller
{
public static void Call()
{
Traced traced = new Traced();
traced.Method1();
traced.Method2();
}
}
public class Traced
{
public void Method1(String name, Int32 value) { }
public void Method2(Object object) { }
}
public class Logger
{
public static void LogStart(MethodInfo method, Object[] parameterValues);
public static void LogEnd(MethodInfo method);
}
How do I invoke Logger.LogStart and Logger.LogEnd for every call to Method1 and Method2 without modifying the Caller.Call method and without adding the calls explicitly to Traced.Method1 and Traced.Method2?
Edit: What would be the solution if I'm allowed to slightly change the Call method?
C# is not an AOP oriented language. It has some AOP features and you can emulate some others but making AOP with C# is painful.
I looked up for ways to do exactly what you wanted to do and I found no easy way to do it.
As I understand it, this is what you want to do:
[Log()]
public void Method1(String name, Int32 value);
and in order to do that you have two main options
Inherit your class from MarshalByRefObject or ContextBoundObject and define an attribute which inherits from IMessageSink. This article has a good example. You have to consider nontheless that using a MarshalByRefObject the performance will go down like hell, and I mean it, I'm talking about a 10x performance lost so think carefully before trying that.
The other option is to inject code directly. In runtime, meaning you'll have to use reflection to "read" every class, get its attributes and inject the appropiate call (and for that matter I think you couldn't use the Reflection.Emit method as I think Reflection.Emit wouldn't allow you to insert new code inside an already existing method). At design time this will mean creating an extension to the CLR compiler which I have honestly no idea on how it's done.
The final option is using an IoC framework. Maybe it's not the perfect solution as most IoC frameworks works by defining entry points which allow methods to be hooked but, depending on what you want to achive, that might be a fair aproximation.
The simplest way to achieve that is probably to use PostSharp. It injects code inside your methods based on the attributes that you apply to it. It allows you to do exactly what you want.
Another option is to use the profiling API to inject code inside the method, but that is really hardcore.
You could achieve it with Interception feature of a DI container such as Castle Windsor. Indeed, it is possible to configure the container in such way that every classes that have a method decorated by a specific attribute would be intercepted.
Regarding point #3, OP asked for a solution without AOP framework. I assumed in the following answer that what should be avoided were Aspect, JointPoint, PointCut, etc. According to Interception documentation from CastleWindsor, none of those are required to accomplish what is asked.
Configure generic registration of an Interceptor, based on the presence of an attribute:
public class RequireInterception : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
if (HasAMethodDecoratedByLoggingAttribute(model.Implementation))
{
model.Interceptors.Add(new InterceptorReference(typeof(ConsoleLoggingInterceptor)));
model.Interceptors.Add(new InterceptorReference(typeof(NLogInterceptor)));
}
}
private bool HasAMethodDecoratedByLoggingAttribute(Type implementation)
{
foreach (var memberInfo in implementation.GetMembers())
{
var attribute = memberInfo.GetCustomAttributes(typeof(LogAttribute)).FirstOrDefault() as LogAttribute;
if (attribute != null)
{
return true;
}
}
return false;
}
}
Add the created IContributeComponentModelConstruction to container
container.Kernel.ComponentModelBuilder.AddContributor(new RequireInterception());
And you can do whatever you want in the interceptor itself
public class ConsoleLoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.Writeline("Log before executing");
invocation.Proceed();
Console.Writeline("Log after executing");
}
}
Add the logging attribute to your method to log
public class Traced
{
[Log]
public void Method1(String name, Int32 value) { }
[Log]
public void Method2(Object object) { }
}
Note that some handling of the attribute will be required if only some method of a class needs to be intercepted. By default, all public methods will be intercepted.
If you write a class - call it Tracing - that implements the IDisposable interface, you could wrap all method bodies in a
Using( Tracing tracing = new Tracing() ){ ... method body ...}
In the Tracing class you could the handle the logic of the traces in the constructor/Dispose method, respectively, in the Tracing class to keep track of the entering and exiting of the methods. Such that:
public class Traced
{
public void Method1(String name, Int32 value) {
using(Tracing tracer = new Tracing())
{
[... method body ...]
}
}
public void Method2(Object object) {
using(Tracing tracer = new Tracing())
{
[... method body ...]
}
}
}
If you want to trace after your methods without limitation (no code adaptation, no AOP Framework, no duplicate code), let me tell you, you need some magic...
Seriously, I resolved it to implement an AOP Framework working at runtime.
You can find here : NConcern .NET AOP Framework
I decided to create this AOP Framework to give a respond to this kind of needs. it is a simple library very lightweight. You can see an example of logger in home page.
If you don't want to use a 3rd party assembly, you can browse the code source (open source) and copy both files Aspect.Directory.cs and Aspect.Directory.Entry.cs to adapted as your wishes. Theses classes allow to replace your methods at runtime. I would just ask you to respect the license.
I hope you will find what you need or to convince you to finally use an AOP Framework.
Take a look at this - Pretty heavy stuff..
http://msdn.microsoft.com/en-us/magazine/cc164165.aspx
Essential .net - don box had a chapter on what you need called Interception.
I scraped some of it here (Sorry about the font colors - I had a dark theme back then...)
http://madcoderspeak.blogspot.com/2005/09/essential-interception-using-contexts.html
I have found a different way which may be easier...
Declare a Method InvokeMethod
[WebMethod]
public object InvokeMethod(string methodName, Dictionary<string, object> methodArguments)
{
try
{
string lowerMethodName = '_' + methodName.ToLowerInvariant();
List<object> tempParams = new List<object>();
foreach (MethodInfo methodInfo in serviceMethods.Where(methodInfo => methodInfo.Name.ToLowerInvariant() == lowerMethodName))
{
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length != methodArguments.Count()) continue;
else foreach (ParameterInfo parameter in parameters)
{
object argument = null;
if (methodArguments.TryGetValue(parameter.Name, out argument))
{
if (parameter.ParameterType.IsValueType)
{
System.ComponentModel.TypeConverter tc = System.ComponentModel.TypeDescriptor.GetConverter(parameter.ParameterType);
argument = tc.ConvertFrom(argument);
}
tempParams.Insert(parameter.Position, argument);
}
else goto ContinueLoop;
}
foreach (object attribute in methodInfo.GetCustomAttributes(true))
{
if (attribute is YourAttributeClass)
{
RequiresPermissionAttribute attrib = attribute as YourAttributeClass;
YourAttributeClass.YourMethod();//Mine throws an ex
}
}
return methodInfo.Invoke(this, tempParams.ToArray());
ContinueLoop:
continue;
}
return null;
}
catch
{
throw;
}
}
I then define my methods like so
[WebMethod]
public void BroadcastMessage(string Message)
{
//MessageBus.GetInstance().SendAll("<span class='system'>Web Service Broadcast: <b>" + Message + "</b></span>");
//return;
InvokeMethod("BroadcastMessage", new Dictionary<string, object>() { {"Message", Message} });
}
[RequiresPermission("editUser")]
void _BroadcastMessage(string Message)
{
MessageBus.GetInstance().SendAll("<span class='system'>Web Service Broadcast: <b>" + Message + "</b></span>");
return;
}
Now I can have the check at run time without the dependency injection...
No gotchas in site :)
Hopefully you will agree that this is less weight then a AOP Framework or deriving from MarshalByRefObject or using remoting or proxy classes.
First you have to modify your class to implement an interface (rather than implementing the MarshalByRefObject).
interface ITraced {
void Method1();
void Method2()
}
class Traced: ITraced { .... }
Next you need a generic wrapper object based on RealProxy to decorate any interface to allow intercepting any call to the decorated object.
class MethodLogInterceptor: RealProxy
{
public MethodLogInterceptor(Type interfaceType, object decorated)
: base(interfaceType)
{
_decorated = decorated;
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase;
Console.WriteLine("Precall " + methodInfo.Name);
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
Console.WriteLine("Postcall " + methodInfo.Name);
return new ReturnMessage(result, null, 0,
methodCall.LogicalCallContext, methodCall);
}
}
Now we are ready to intercept calls to Method1 and Method2 of ITraced
public class Caller
{
public static void Call()
{
ITraced traced = (ITraced)new MethodLogInterceptor(typeof(ITraced), new Traced()).GetTransparentProxy();
traced.Method1();
traced.Method2();
}
}
You can use open source framework CInject on CodePlex. You can write minimal code to create an Injector and get it to intercept any code quickly with CInject. Plus, since this is Open Source you can extend this as well.
Or you can follow the steps mentioned on this article on Intercepting Method Calls using IL and create your own interceptor using Reflection.Emit classes in C#.
I don't know a solution but my approach would be as follows.
Decorate the class (or its methods) with a custom attribute. Somewhere else in the program, let an initialization function reflect all types, read the methods decorated with the attributes and inject some IL code into the method. It might actually be more practical to replace the method by a stub that calls LogStart, the actual method and then LogEnd. Additionally, I don't know if you can change methods using reflection so it might be more practical to replace the whole type.
You could potentially use the GOF Decorator Pattern, and 'decorate' all classes that need tracing.
It's probably only really practical with an IOC container (but as pointer out earlier you may want to consider method interception if you're going to go down the IOC path).
you need to bug Ayende for an answer on how he did it:
http://ayende.com/Blog/archive/2009/11/19/can-you-hack-this-out.aspx
AOP is a must for clean code implementing, however if you want to surround a block in C#, generic methods have relatively easier usage. (with intelli sense and strongly typed code) Certainly, it can NOT be an alternative for AOP.
Although PostSHarp have little buggy issues (i do not feel confident for using at production), it is a good stuff.
Generic wrapper class,
public class Wrapper
{
public static Exception TryCatch(Action actionToWrap, Action<Exception> exceptionHandler = null)
{
Exception retval = null;
try
{
actionToWrap();
}
catch (Exception exception)
{
retval = exception;
if (exceptionHandler != null)
{
exceptionHandler(retval);
}
}
return retval;
}
public static Exception LogOnError(Action actionToWrap, string errorMessage = "", Action<Exception> afterExceptionHandled = null)
{
return Wrapper.TryCatch(actionToWrap, (e) =>
{
if (afterExceptionHandled != null)
{
afterExceptionHandled(e);
}
});
}
}
usage could be like this (with intelli sense of course)
var exception = Wrapper.LogOnError(() =>
{
MessageBox.Show("test");
throw new Exception("test");
}, "Hata");
Maybe it's to late for this answer but here it goes.
What you are looking to achieve is built in MediatR library.
This is my RequestLoggerBehaviour which intercepts all calls to my business layer.
namespace SmartWay.Application.Behaviours
{
public class RequestLoggerBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger _logger;
private readonly IAppSession _appSession;
private readonly ICreateLogGrain _createLogGrain;
public RequestLoggerBehaviour(ILogger<TRequest> logger, IAppSession appSession, IClusterClient clusterClient)
{
_logger = logger;
_appSession = appSession;
_createLogGrain = clusterClient.GetGrain<ICreateLogGrain>(Guid.NewGuid());
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var name = typeof(TRequest).Name;
_logger.LogInformation($"SmartWay request started: ClientId: {_appSession.ClientId} UserId: {_appSession.UserId} Operation: {name} Request: {request}");
var response = await next();
_logger.LogInformation($"SmartWay request ended: ClientId: {_appSession.ClientId} UserId: {_appSession.UserId} Operation: {name} Request: {request}");
return response;
}
}
}
You can also create performance behaviours to trace methods that take too long to execute for example.
Having clean architecture (MediatR) on your business layer will allow you to keep your code clean while you enforce SOLID principles.
You can see how it works here:
https://youtu.be/5OtUm1BLmG0?t=1
Write your own AOP library.
Use reflection to generate a logging proxy over your instances (not sure if you can do it without changing some part of your existing code).
Rewrite the assembly and inject your logging code (basically the same as 1).
Host the CLR and add logging at this level (i think this is the hardest solution to implement, not sure if you have the required hooks in the CLR though).
The best you can do before C# 6 with 'nameof' released is to use slow StackTrace and linq Expressions.
E.g. for such method
public void MyMethod(int age, string name)
{
log.DebugTrace(() => age, () => name);
//do your stuff
}
Such line may be produces in your log file
Method 'MyMethod' parameters age: 20 name: Mike
Here is the implementation:
//TODO: replace with 'nameof' in C# 6
public static void DebugTrace(this ILog log, params Expression<Func<object>>[] args)
{
#if DEBUG
var method = (new StackTrace()).GetFrame(1).GetMethod();
var parameters = new List<string>();
foreach(var arg in args)
{
MemberExpression memberExpression = null;
if (arg.Body is MemberExpression)
memberExpression = (MemberExpression)arg.Body;
if (arg.Body is UnaryExpression && ((UnaryExpression)arg.Body).Operand is MemberExpression)
memberExpression = (MemberExpression)((UnaryExpression)arg.Body).Operand;
parameters.Add(memberExpression == null ? "NA" : memberExpression.Member.Name + ": " + arg.Compile().DynamicInvoke().ToString());
}
log.Debug(string.Format("Method '{0}' parameters {1}", method.Name, string.Join(" ", parameters)));
#endif
}
I am attempting to write a job queuing system using C#.
Suppose I have the following class which represents a job to perform at a later date:
public class TestJob : QueuableJob
{
private readonly string _t;
private readonly string _e;
public TestJob(string t, string e)
{
_t = t;
_e = e;
}
public Task PerformWork(ITestService testService)
{
testService.Message($"Hello: {_t} {_e}");
return Task.CompletedTask;
}
}
I would like to be able to call something like:
JobQueueService.EnqueueJob(new TestJob("value1", "value2"));
In order to queue a job, I need serialize the parameters passed to the constructor of TestJob, so I can store them in a persistence layer (eg a database) and later deserialize them. Then I can instantiate the class and execute PerformWork. I would like to handle this as seamless as possible in my library so the end-user writing their "Job" classes doesn't have to worry about adding specific things for serialization.
I cannot figure out a way to "intercept" the parameters passed to the TestJob class without either losing strict typing (eg I could use params object[] parameters), or forcing the end user to implement some other code to help with serialization.
Currently, the most elegant solution I can think of (for the end user), is something like this:
public class TestJob : QueuableJob
{
private readonly string _t;
private readonly string _e;
public TestJob(string t, string e) : base(t,e)
{
_t = t;
_e = e;
}
public Task PerformWork(ITestService testService)
{
testService.Message($"Hello: {_t} {_e}");
return Task.CompletedTask;
}
}
However, that would require the developer to remember to pass all of their parameters to base() (like base(t,e) in the example above). The compiler will not complain if they forget to do this, so it could be source of tricky bugs.
I've also tried to get the information using System.Diagnostics.StackTrace in the QueuableJob constructor, however it don't believe I can obtain the values of the parameters from the stack.
Is there any way I can use reflection to "intercept" what is being passed into the TestJob constructor?
I'm not sure I think this is necessarily the best way to approach the problem, but since you know more about this problem than I do, here is a way to get the names of the constructor parameters for a type:
var constructors = typeof(TestJob).GetConstructors();
var constructor = constructors[0];
foreach (var param in constructor.GetParameters())
{
Console.WriteLine($"Argument: {param.Position} is called {param.Name} and is a {param.ParameterType}");
}
Likewise, you can use reflection to retrieve the values on runtime and use Activator.CreateInstance to instantiate the objects again.
I have a C# code
private class EvaluationTask : Task<Solution> {
private Problem problem_;
private Solution solution_;
public EvaluationTask(Problem problem, Solution solution)
{
problem_ = problem;
solution_ = solution;
}
}
Now, I am getting error System.Threading.Tasks.Task<> does not contain constructor that takes 0 arguments. From previous answers posted, I found that one has to define empty constructor in the base class. But since my base class is Task<>, how do I add an empty constructor to it?
Any help would be highly appreciated!
Edit: I have to inherit task<> because I have to use the method EvaluationTask in a code:
taskList_ = new List<Task<Solution>>();
taskList_.Add(new MultithreadedEvaluator.EvaluationTask (problem_, solution));
I don't know about task composition, so if it is necessary can anyone help with that? Or if by any way I can avoid inheriting Task and still implement taskList_.Add()?
When you inherit from a class, in your constructors you need to call any of the constructors of the base class. In your case, since you aren't calling any constructor, the compiler try to call a parameterless constructor of the base class, but Task<> haven't a parameterless constructor.
As you can read here, inheriting from Task<> probably isn't a good idea, but you can do something like this:
class EvaluationTask : Task<Evaluation>
{
public EvaluationTask()
: base(DoWork) { }
private static Evaluation DoWork()
{
//...
}
}
When using Task<T>, you must supply the Func<> or Action<> delegate (i.e., function pointer to the desired work to perform) as a constructor argument. It is indeed somewhat unfortunate that there isn't any constructor which lets you bypass this requirement and supply the delegate at a later time (yet obviously still prior to calling Start()), since this severely hampers the ability to extend the Task and Task<TResult> classes via inheritance altogether.
The reason it's a crippling omission is that no delegate you supply as a constructor argument can possibly directly incorporate a reference to the instance you are trying to construct, since that instance (again, obviously) doesn't exist yet, chicken/egg style.
Hence #Arturo's answer, which shows that you can, in fact, supply a static delegate, but since such a delegate has no obvious way of referencing one particular Task instance, it essentially defeats the purpose of inheriting from Task in the first place.
--- reflection disclaimer ---I've been using this technique in my own projects for years on .NET Framework 4.7 (desktop) with no problems whatsoever, but please note that code which uses reflection to access non-public behavior is subject to breakage if the .NET internals change in a later version. You have been warned.
Here's a more flexible workaround for the problem, a general-purpose abstract base class for Task<TResult> which allows you to provide the desired work code in the normal way for derived type hierarchies: as an instance method override. This is a reflection solution; the way it works is to provide a dummy "placeholder" delegate to the base constructor call, but then immediately in the constructor body, swap it out for the "real," desired abstract instance work method, which at that point is no longer unknowable or rather unbindable.
abstract class TaskBase<TResult> : Task<TResult>
{
readonly static FieldInfo m_action =
typeof(Task).GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic);
readonly static Func<TResult> _dummy = () => default;
public TaskBase(CancellationToken ct, TaskCreationOptions opts)
: base(_dummy, ct, opts) =>
m_action.SetValue(this, (Func<TResult>)function);
public TaskBase(CancellationToken ct)
: this(ct, TaskCreationOptions.None)
{ }
public TaskBase(TaskCreationOptions opts)
: this(default, opts)
{ }
public TaskBase()
: this(default, TaskCreationOptions.None)
{ }
protected abstract TResult function(); // <-- override with your work code
};
To use this, simply inherit from TaskBase<TResult>, and override the abstract method function() to implement your task work logic. There is no need for a version of this base class where the work function accepts a AsyncState argument/parameter(s), since you can simply declare all the relevant context for the specific work instance as additional instance fields (and instance methods, and instance properties...) in your derived class. So the constructor variations I declared exactly match those provided by Task<TResult>, but minus the 'function' and 'state' arguments. And finally, don't forget to call Start() when your packaged work instance is ready to go!
The above is a actually a simplified version of the TaskBase<TResult> code I've had much success with. My enhanced version avoids creating the Func<TResult> delegate which must be created for each TaskBase instance in order to "wrap" the C# method function() as an instance delegate. Instead of initially providing a 'dummy' delegate to the base constructor, I always provide (the same) static delegate, a singleton which acts as a "thunk" that universally reinterprets, or "upcasts" a Task<TResult>'s AsyncState object as a pertinent TaskBase<TResult> instance, and then calls function() directly on that instance. Like so:
static Func<Object,TResult> thunk = obj => ((TaskBase<TResult>)obj).function();
So fn_redirect is the only "excess" delegate we need to create once at startup, and this singleton is always passed-in as the base constructor work delegate. Now as with that constructor argument, the "async state" object is also only passed in as a constructor argument and normally cannot later be changed. We don't need a "dummy" in this approach, because you can--and should--pass in 'null' for state. Similar to before we use reflection to set a field, but this time it's m_stateObject field instead of m_action, to replace the 'null' value we just installed for the instance this pointer:
public TaskBase(CancellationToken ct, TaskCreationOptions opts)
: base(thunk, default(Object), ct, opts)
{
m_stateObject.SetValue(this, this);
}
Voila, allocating one extra delegate for each TaskBase instance is avoided. Finally, recall that there are no adverse loss of capability when co-opting the state object for the purpose of this enhancement because as I mentioned earlier, the whole AsyncObject argument-passing mechanism is unnecessary when you entirely control the derived class you are writing.
Here is an inheritable class that inherits from Task<T>, and allows delayed assignment of the task's function. The constructor takes no arguments. The function is assigned by the property Function.
public class FlexibleTask<T> : Task<T>
{
private readonly Helper _helper;
public Func<T> Function { set { _helper.SetFunction(value); } }
public FlexibleTask() : base(GetFunction())
{
this._helper = TempHelper;
TempHelper = null;
}
private static Func<T> GetFunction()
{
Func<T> function = Default;
var helper = new Helper();
helper.SetFunction = f => function = f;
TempHelper = helper;
return () => function();
}
private static readonly Func<T> Default = () =>
throw new InvalidOperationException("Function is not set.");
[ThreadStatic] private static Helper TempHelper;
private class Helper
{
public Action<Func<T>> SetFunction {get; set;}
}
}
Usage Example:
public class EvaluationTask : FlexibleTask<int>
{
}
var task = new EvaluationTask();
task.Function = () => 13;
task.Start();
var result = await task;
Console.WriteLine($"Result: {result}");
Output:
Result: 13
In my program I have multiple instances of a specific class Tracer (A1,B2,C3 etc). Using a listbox called tracerListBox, the user will determine which tracer they want to use.
Lets say each tracer has a constructor named family.
I know that if I wanted to access the family of, say, A1 I would simply type:
A1.family
However, I want to write code that accomplishes something like this:
tracerListBox.Text.family
Is there a way to pass a user-determined value to a constructor? I essentially want the user to determine which instance of Class Tracer to use and then use that information to pull all of the information about that specific tracer.
Thanks in advance for any assistance you can provide.
What you are looking for is a factory method, sometimes also called a virtual constructor (which is not technically correct, because it's neither a constructor nor a virtual method).
Instead of calling a constructor, you call a static method that calls a constructor of the class determined by the arguments passed in.
interface ITracer {
void Trace(string s);
}
class TracerA : ITracer {
public void Trace(string s) {
// ...
}
}
class TracerB : ITracer {
public void Trace(string s) {
// ...
}
}
class TracerFactory {
public static ITracer Make(string name) {
if (name.Equals("A")) return new TracerA();
if (name.Equals("B")) return new TracerB();
throw new ApplicationException("Unknown: "+name);
}
}
Much of the detail to actually make a decision is missing from your question. However, we can point you in the general directions that may answer your question.
Reflection would definitely help. Look at object.GetType() to start.
Check out different Dependency Injection or Inversion of Control (IOC) libraries. They may be just what you need.
Are you looking for something like this:
string myType = "MyNamespace." + tracerListBox.Text + ", MyAssembly";
var = Type.GetType( myType );
var property = t.GetProperty("family", BindingFlags.Static);
I have a service responsible for subscribing to EWS for new mail notification. I've created an interface for the service in order to mock it and test a dummy implementation. However, I'm running into a wall whenever I try to manually tell what my events are supposed to do.
Here is my concrete implementation.
public interface IExchangeService
{
void Subscribe();
}
public class ExchangeServiceSubscriber : IExchangeService
{
private readonly ExchangeService _exchangeService;
private readonly IConsumer<IEmail> _consumer;
public ExchangeServiceSubscriber(
ExchangeService exchangeService,
IConsumer<IEmail> consumer)
{
_exchangeService = exchangeService;
_consumer = consumer;
}
public void Subscribe()
{
// code to subscribe
streamingConnection.OnNotificationEvent += OnEvent;
streamingConnection.Open();
}
public void OnEvent(object sender, NotificationEventArgs args)
{
foreach (NotificationEvent triggeredEvent in args.Events)
{
if (triggeredEvent is ItemEvent)
{
var propertySet = new PropertySet(ItemSchema.UniqueBody, ItemSchema.Attachments)
{
RequestedBodyType = BodyType.Text
};
EmailMessage email = EmailMessage.Bind(args.Subscription.Service,
((ItemEvent)triggeredEvent).ItemId, propertySet);
_consumer.Consume(new ExchangeEmail { Body = email.UniqueBody });
}
}
}
}
And unfortunatly, almost every class in EWS is either sealed or has an internal constructor which really limits how I decouple them, it seems. I've attempted to set the expectation for NotificationEventArgs (for example) but it uses an internal constructor.
Here is some ideas I've been fiddling with. You can read about mocking events here.
mock.Setup(x => x.OnEvent(new object(), new NotificationEventArgs()));
Issue with that is NotificationEventArgs uses an internal constructor.
I could see getting this working with some sort of wrapper but I'm not exactly sure what it would look like. One of the big problems is the way EWS is made pretty much prevents anyone from manually injecting dependencies. I'm essentially trying to test that whenever event OnEvent fires that the email will actually get consumed. Also, while I would like to test this functionality I'm not sure it's worth fighting EWS every step of the way.
Let's first see, what you can't do:
You can't subclass NotificationEventArgs because the ctor is internal.
You can't create an instance directly for the same reason.
So basically, you can't create an instance of this class using the "normal way". I assume you already checked for a factory method or class?
This leaves us with only one option: Instantiate the class using reflection, e.g. with the help of the Activator.CreateInstance method: Unit testing exception handling for third party exceptions with internal constructors, like so:
mock.Setup(x => x.OnEvent(new object(),
Activator.CreateInstance(typeof(NotificationEventArgs),
BindingFlags.NonPublic | BindingFlags.Instance,
null,
null,
null))
);