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.
Related
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.
What is a good (object oriented) way of setting a property of a class which implements an interface, when that property doesn't always exist in all classes that implement that same interface?
e.g.
Let's say I have an interface
public interface IDataRepository {
public DataStructure GetData(); // DataStructure is an arbitrary class, doesn't matter for this example
}
Now I also have two classes that inherit from this
public class DatabaseRepository : IDataRepository {
public DataStructure GetData()
{
// get data from database
}
}
and
public class FileRepository : IDataRepository {
public string WorkingFolder { get; set; }
public DataStructure GetData() {
// get data from files
}
}
Now my client method doesn't necessarily know what the repository is but here's what I want to do...
private DataStructure ReadData(IDataRepository repository)
{
repository.WorkingFolder = #"C:\Data"; // What is the best way of doing this?
return repository.GetData();
}
obviously the above code won't work and I could do...
if (repository is FileRepository) {
((FileRepository)repository).WorkingFolder = #"C:\Data";
}
or add WorkingFolder as a property of the interface (and therefore all the classes that implement it) even though in most cases it's irrelevant.
but both of these (esp. the first one) seem very inelegant and not very object oriented. What is the oop way of doing this kind of thing?
Edit
The obvious question is if the method doesn't know what repository is, how can it know the correct value for WorkingFolder... But the above is an over-simplification of what I'm trying to do, so let's just say it can find out...
Apparently your ReadData method can't actually accept any type of repository. It is only able to handle a FileRepository. That's what it expects, and that's what it needs to do its job. Given that, that's what it should actually accept as its parameter, rather than an interface that doesn't actually provide a contract that is sufficient for it to do its job.
The entire point of having an interface is so that anyone using that interface can use it without caring what the implementation is. So if you do want to use the interface you need to include enough information in the interface's definition such that it provides every operation that anyone using the interface needs, otherwise you're better off just not using it at all (at least for that specific operation).
As for the specific example given, you should probably just be providing an already configured repository, that has whatever values it needs in order to allow this method to do its work, as a parameter. It doesn't make sense for a method that's reading a value from an arbitrary repository to be configuring that repository at all. That is, if it really is reading something from an arbitrary repository.
As others have said in the comments, you should initialise these properties in the constructor. This is where you know what type you're creating, so you also know what arguments its constructor requires / can set those there.
Once you've initialised the object, you can just pass it around / have anything using that class operate against its interface.
Example:
public void Main(string[] args)
{
var myRepo = new FileRepository(args[0]); //Here's where we set the working directory
var myThing = new Thing();
var data = myThing.ReadData(myRepo);// of course, the current implementation means you could just call `myRepo.GetData()` directly, since ReadData just passes out the same response; but presumably that method adds some additional value..
Console.WriteLine(data.ToString());
}
Supporting Code
public class DatabaseRepository : IDataRepository {
DbConnection connection; //you may want a connection string or something else; going with this type just to illustrate that this constructor uses a different type to the FileRepo's
public DatabaseRepository(DbConnection connection)
{
this.connection = connection;
}
public DataStructure GetData()
{
// get data from database
}
}
public class FileRepository : IDataRepository {
public string WorkingFolder { get; set; } //Do you need set? Generally best to keep it constant after initialisation unless there's good reason to change it
public FileRepository (string workingFolder)
{
this.WorkingFolder = workingFolder;
}
public DataStructure GetData() {
// get data from files
}
}
How do I call the code that creates the class
i.e. maybe you've implemented a really basic factory pattern like so, and want to know how to provide arguments:
public class DataRepositoryFactory
{
Type baseType = typeof(IDataRepository);
IDictionary<string, Type> typeMap = new Dictionary<string, Type>() {
{"File", typeof(FileRepository) }
,{"Db", typeof(DatabaseRepository) }
}
public void RegisterType(string typeName, Type type)
{
if (!baseType.IsAssignableFrom(type)) throw new ArgumentException(nameof(type));
typeMap.Add(typeName, type);
}
public IDataRepository GetDataRepository(string typeName)
{
return (IDataRepository)Activator.CreateInstance(typeMap[typeName]);
}
}
(For a more complex example of a factory, see https://web.archive.org/web/20140414013728/http://tranxcoder.wordpress.com/2008/07/11/a-generic-factory-in-c).
I.e. in this scenario, when you call the factory you know what type you want, but you're only giving it a string to name/identify that class. You could add a params object[] args to your GetDataRepository method, allowing you to call it like so:
var myRepo = myDataRepositoryFactory.GetDataRepository("File", "c:\somewhere\something.dat");
That's a good approach / is actually what's used on the linked example above. However, it means that your call to this code differs for different types; since if we use variables instead of hardcoded values as in the above example we can't simply do the below, since myRepoType could be set to "Db", whilst "myFilePath" would be a string:
var myRepo = myDataRepositoryFactory.GetDataRepository(myRepoType, myFilePath);
That's fixable by calling:
var myRepo = myDataRepositoryFactory.GetDataRepository(myRepoType, myArgs);
i.e. where myArgs is an object[], giving all of the values required in the desired order to initialise the type. The piece to populate object[] with the required values could then take place at the same point at which you decided you wanted the type to be a file repo vs database repo. However, this approach isn't that clean / casting to and from objects stops you from getting help from the compiler.
So how do I improve things?
There are a few options. One is to replace the need to use object[] by instead creating a type to hold your arguments. e.g.
public interface IDataRepositoryConfiguration
{
//nothing required; this is just so we've got a common base class
}
public class FileRepositoryConfiguration: IDataRepositoryConfiguration
{
public string WorkingFolder {get;set;}
}
public class FileRepository : IDataRepository {
public FileRepository (IDataRepositoryConfiguration configuration)
{
var config = configuration as FileRepositoryConfiguration;
if (config == null) throw new ArgumentException(nameof(configuration)); //improve by having different errors for null config vs config of unsupported type
this.WorkingFolder = config.WorkingFolder;
}
//...
}
This still has some issues; i.e. we may pass a DatabaseRepositoryConfiguration as our IRepositoryConfiguration when creating a FileRepository, in which case we'd get the AgumentNullException at runtime; but this does avoid issues should parameters change order, and makes it less of a headache to code / debug.
Could it be further improved?
Dependency Injection offers one solution. This could be used along the lines of the code below (i.e. you create instances of each of your classes, providing the required arguments, and give each instance a name, so that you can later fetch that instantiation. Exactly what that code looks like would depend on the dependency injection library you used:
//setting up your repositories
var container = new Container();
container.Configure(config =>
{
// Register stuff in container, using the StructureMap APIs...
config.For<IDataRepository>().Add(new FileRepository("\\server\share\customers")).Named("customers");
config.For<IDataRepository>().Add(new FileRepository("\\server\share\invoices")).Named("invoices");
config.For<IDataRepository>().Add(new DatabaseRepository(new DbConnection(configurationString))).Named("persist");
config.For<IDataRepository>().Use("persist"); // Optionally set a default
config.Populate(services);
});
//then later when you need to use it...
public DataStructure ImportCustomers(IContainer container)
{
var customerRepo = container.GetInstance<IDataRepository>("customers");
return customerRepo.GetData();
}
I'm sure there are many other approaches, and exactly what approach to use depends on how your program will operate. Hopefully the above is enough to get you past your current problem; but if you find you're still struggling please post a new question with more detail / saying where you're still having issues having considered these points.
If possible, I'd just put the value for that property in the constructor or create a subinterface, like others suggested.
If it's not possible, C# 7.X (don't remember the exact minor version) has a nice code structure for conditional casting:
IDataRepository repo = new FileRepository();
if (repo is FileRepository fileRepo)
{
fileRepo.WorkingFolder = "some dir";
}
However in your case, you should probably rethink your architecture and always pass (or even better always create) a repository object which is ready to be used.
a) Put it into the Inferface definitions. Deal with any "NotImplemented" Exceptions. You always have to expect those with Interfaces anyway.
For example, IEnumerable has a Reset() function. But in most cases it is not implemented. It is not even supposed to be implemented in most cases. Afaik it is only there for Backwards Compatabilty with some old COM stuff.
b) make a sub-interface just for the property
c) Verify the Interface is properly implemented via is checks (throw exceptions thows if nessesary, like Array.Sort will throw a InvalidOperation one), generic constraints, proper argument types and the like.
I'm trying to find out the best (nicest) way to pass an argument to the constructor of a child object of an auto-resolved parameter.
Why?
Because I have a program that does almost all its computations against the same "production" database (defined in the config file, so no argument required). But now needs to run some work on a 'copy' of this database. Therefore requiring a different connection string.
The connection string can be supplied on the constructor, and is not known at compile time. The problem is that I can't (or do not know how to) simply access this constructor because it is buried deep inside the generated items.
Consider the following (simplified) code snippet:
public class Example
{
protected readonly IGenerateSomethingFactory Factory;
public Example(IGenerateSomethingFactory factory)
{
Factory = factory;
}
public Task DoSomething(string ConnectionString, string a, string b)
{
//needs to run somehow using the supplied connection string ...
return Task.Run(() => Factory.CreateSomething().Execute(a, b));
//= Task.Run(() => new Something(new UnitOfWork(new DataContext(ConnectionString))).Execute(a, b));
}
public Task DoSomething(string a, string b)
{
//needs to run using the default connection string (defined in config)
return Task.Run(() => Factory.CreateSomething().Execute(a, b));
}
}
The problem lays in the first DoSomething(...) function.
Note: The Castle Windsor installer looks like this:
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IGenerateSomethingFactory>().AsFactory());
container.Register(Classes.FromThisAssembly().InNamespace("x").WithService.FirstInterface());
}
}
I'm looking for a solution that:
is thread safe
is easy to understand (if not easy to think of)
allows refactoring (so no named arguments like "conString" )
does not require changes to other non-relevant code
(i.e. setting properties public ... )
does not call new or container.Resolve<>()
I have been looking into selection handlers, but have not really found what I was looking for.
PS: I'm using Castle Windsor 3.3.0
PPS: this is my first question, I can provide more example code but thought I should restrict to the minimum ... so let me know if I need to do so.
From your example, it looks like all you need to do is add a parameter to your typed factory's CreateSomething method:
public interface IGenerateSomethingFactory
{
ISomething CreateSomething(string connectionString);
}
Then add that as a parameter to your ISomething implementation:
public class Something : ISomething
{
public Something(string connectionString)
{
}
}
Note how the parameter to CreateSomething and Something's constructor are named the same. This is the default behavior for parameter matching.
Now, you just pass the value along in your call to DoSomething:
public Task DoSomething(string ConnectionString, string a, string b)
{
return Task.Run(() => Factory.CreateSomething(ConnectionString).Execute(a, b));
}
Based on your added code, what you're trying to do isn't immediately possible. In a nutshell, you have this resolution hierarchy:
IGenerateSomethingFactory.Create(string constring)
Something.ctor(IUnitOfWork uow)
UnitOfWork.ctor(IDataContext context)
DataContext.ctor(string constring)
You're trying to pass the argument from the call to Create down to the constructor of DataContext.
For a way to enable this, see my answer (to my own question). I do this by changing the default behavior of Windsor to pass the factory creation parameters down to all objects being resolved instead of just the first.
First, create this class to change this behavior:
public class DefaultDependencyResolverInheritContext : DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
{
if (parameterType.ContainsGenericParameters)
{
return current;
}
return new CreationContext(parameterType, current, true);
}
}
Then supply it when creating the container:
var kernel = new DefaultKernel(
new DefaultDependencyResolverInheritContext(),
new NotSupportedProxyFactory());
var container = new WindsorContainer(kernel, new DefaultComponentInstaller());
That's it. Now when you call your Create method, the constring parameter will be passed down to all objects being registered. Obviously this can cause problems if you have parameters that are the same name! In your case, this is an "ambient" parameter (my term) so you could just document this behavior/parameter name and call it a day.
I'd love to see another approach to this, save for creating factories for all the intermediate types.
Is there a way around to pass non-constant complex or primitive values to an attribute?
public class SomeClass
{
private SomeOtherClass _someOtherClass = new SomeOtherClass();
private int _somePrimitiveVariable = CalculateSomeValue();
[MyAttribute(InputValue = _someOtherClass)
public void MyMethod()
{
//Some stuff
}
//Or can it be like this?
[MyAttribute(InputValue = _somePrimitiveVariable)
public void MyMethod()
{
//Some stuff
}
}
Attributes are resolved at compile time, so the comments saying "no" are mostly correct.
However, if you can't rework your design, there are limited workarounds. If this is a universal property you wish to set (that will apply to every user of the attribute), your best bet might be having an initializer method in your code call a configuration method on the attribute. This would look vaguely similar to Can C# Attributes access the Target Class?. Ugly, but might work in specific circumstances.
I'm trying to refactor a method that parses through a file. To support files of arbitrary size, the method using a chunking approach with a fixed buffer.
public int Parse()
{
// Get the initial chunk of data
ReadNextChunk();
while (lengthOfDataInBuffer > 0)
{
[parse through contents of buffer]
if (buffer_is_about_to_underflow)
ReadNextChunk();
}
return result;
}
The pseudo code above is part of the only public non-static method in a class (other than the constructor). The class only exists to encapsulate the state that must be tracked while parsing through a file. Further, once this method has been called on the class, it can't/shouldn't be called again. So the usage pattern looks like this:
var obj = new MyClass(filenameToParse);
var result = obj.Parse();
// Never use 'obj' instance again after this.
This bugs me for some reason. I could make the MyClass constructor private, change Parse to a static method, and have the Parse method new up an instance of Parse scoped to the method. That would yield a usage pattern like the following:
var result = MyClass.Parse(filenameToParse);
MyClass isn't a static class though; I still have to create a local instance in the Parse method.
Since this class only has two methods; Parse and (private) ReadNextChunk, I'm wondering if it might not be cleaner to write Parse as a single static method by embedding the ReadNextChunk logic within Parse as an anonymous method. The rest of the state could be tracked as local variables instead of member variables.
Of course, I could accomplish something similar by making ReadNextChunk a static method, and then passing all of the context in, but I remember that anon methods had access to the outer scope.
Is this weird and ugly, or a reasonable approach?
This maybe suitable more to code review.
However, these are my comments about your design:
I don't think it will matter much about obj instance only used once. If you bugged with it, there are 2 ways to trick it:
Use of another method such as:
public int Parse()
{
var obj = new MyClass(filenameToParse);
return obj.Parse();
}
Make the MyClass implement IDisposable and wrap it in using statement. I don't recommend this since usually IDisposable has logic in their Dispose() method
I think it is better to make your MyClass accept parameter in Parse to Parse(string fileNameToParse). It will make MyClass as a service class, make it stateless, reusable and injectable.
Regarding impact to static class. First it add coupling between your consumer and MyClass. Sometimes if you want to test / unit test the consumer without using the MyClass parser, it will be hard / impossible to mock the MyClass into something you want.
All you need is a static parse method that creates an instance, much like what you suggest in your question
public class MyClass
{
// your existing code.... but make the members and constructor private.
public static int Parse(string filenameToParse)
{
return new MyClass(filenameToParse).Parse();
}
}
then
just use it like you suggest...
var result = MyClass.Parse(filenameToParse);
MyClass isn't a static class though; I still have to create a local
instance in the Parse method.
You don't need a static class to be able to leverage static methods. For example this works fine:
public class MyClass
{
public static string DoStuff(string input)
{
Console.WriteLine("Did stuff: " + input);
return "Did stuff";
}
}
public class Host
{
public void Main()
{
MyClass.DoStuff("something");
}
}