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);
Related
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 have a DI container and I want to pass in arguments to the constructor, via the DI container.
ie,
public interface IPerson { }
public class Person : IPerson {
private int _personId;
Person() { _personId = 0; }
Person(int id) { _personId = id; }
}
...
Container.Register(Component.For<IPerson>().ImplementedBy<Person>().Lifestyle.Transient);
...
//Person is already available
Container.Resolve<Person>(55);
//Person is not available
Container.Resolve<Person>();
This is basically what I want to do. Sometimes I need a new class created, sometimes I already have the class available. How would I achieve this please?
I have thought that I might be able to use dynamic parameters, but I am not sure how.
Thank you in advance.
A Factory pattern would make the solution elegant, however, this adds a bunch of complexity to my application, when all that is needed is a very simple solution which will work just as well.
Passing in a single integer in myself is far far easier than writing a whole factory to do the same job.
You can pass an anonymous type to the Resolve method which specifies the parameter values to use:
container.Resolve<IPerson>(new { id = 5 });
However, if you creating instances of Person at various points in your application, then you don't want to be referencing the container, so you should use a PersonFactory instead which resolves via the container. Have a look at the Typed Factory Facility.
this is my example how to pass params to constructor (DI contailer is unity):
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<ILogger, FileLogger>(new InjectionConstructor(new[] { "c:\\myLog.txt" }));
ILogger logger = container.Resolve<FileLogger>();
logger.Write("My message");
Console.ReadLine();
}
According "Sometimes I need a new class created, sometimes I already have the class available. How would I achieve this please?" - try to implement Factory Pattern
Im currently trying to build a Fluent Interface for a ServiceLocator. To ensure that each the developer can easily setup 1-to-n mappings
I'd like something like this
ServiceLocator.Instance.For<IFoo>(Use<Foo>(), Use<FooBar>());
Singleton is workin fine... the methodsignature for the For method looks like this
public void For<TInterface>(params type[] services)
{
// ...
}
So I was looking for something like a global method
C# has some global methods, all methods which are defined on System.Object. But when I create a new generic ExtensionMethod on System.Object, the method will not be visible.
public static class MyExtensions
{
public static void Use<T>(this Object instance)
{
// ..
}
}
MethodChaining would be the alternative, but this approach looks sexy :D
Has anyone an idea?
Well, actually when I create an extension method for Object, it is visible. As in,
public static class Extensions
{
public static void doStuff<T>(this T myObject)
{
}
}
class Program
{
static void Main(string[] args)
{
int a = 5;
a.doStuff();
string b = "aaa";
b.doStuff();
List<int> c = new List<int>() { 1, 2, 3, 10 };
c.doStuff();
Extensions.doStuff(c);
}
}
Did I misunderstand your question?
You need to add a using statement for the namespace containing your extension method in order for it to be visible. Adding extension methods to object is rarely a good idea.
EDIT:
Okay, now I understand what you're asking. In order to use an extension method you need an instance. You're asking for a static extension method on object (Equals and ReferenceEquals are static methods), and that's not possible. If you define an extension method on object, it will be available on all instances and I'm sure that's not what you want.
public static class ObjectExtensions
{
public static string TypeFullName(this object obj)
{
return obj.GetType().FullName;
}
}
static void Main(string[] args)
{
var obj = new object();
Console.WriteLine(obj.TypeFullName());
var s = "test";
Console.WriteLine(s.TypeFullName());
}
Service Locator is widely considered to be an anti-pattern. Also, a common registration interface is widely considered to be an unsolvable problem unless you are requiring use of a specific container.
Looking past these two questionable decisions, you can remove the need for the global method by defining overloads of For which accept multiple type arguments:
ServiceLocator.Instance.For<IFoo, Foo, FooBar>();
The For methods would look like this:
public void For<TInterface, TImplementation>()
public void For<TInterface, TImplementation1, TImplementation2>()
...
You have to define an overload for each type count, but it requires the minimal syntax and maximum amount of discoverability. For reference, the .NET Framework's Action and Func types support 9 type arguments.
After writing this out, though, I wonder if I misunderstood the question: why would you specify multiple implementations for the same interface? Wouldn't that lead to ambiguity when resolving IFoo?
.Net 3.5 sp1 available type question ...
Is it possible to "get a handle" or reference to the actual instance of an assembly that called a method? I can get the executing and calling assembly via reflection, but what I'm after is not so much the assembly, but the INSTANCE of that assembly that called method.
Simple example (maybe):
interface IBob
{
int Id { get; }
void Foo();
}
public class Bob : IBob
{
private int _id = 123;
public int Id
{
get { return _id; }
}
public void Foo()
{
new OtherAssemblyClass().Bar();
}
}
public class OtherAssemblyClass
{
public void Bar()
{
//
// what I want to do here is get a reference
// to the calling INSTANCE of IBob and determine
// Bob's Id ... so something like:
//
// int Id = (System.XXX.GetCallingAssemblyInstance() as IBob).Id;
//
//
}
}
The real situation is a bit more complex than this, and precludes the obvious passing of IBob instance as a parameter in OtherAssemblyClass.Bar(), although that may be end result.
Entirely possible I'm just being stupid too, and not seeing obvious. 2 x 4 corrections to skull also welcome.
Unfortunately you can't get the instance unless it's passed in. You can find out what's calling your method by using the StackTrace.
PostSharp is the only way I would know of to make that work. Take a look at the InstanceBoundLaosEventArgs class. Warning: this is a pretty big deal, and a serious addition to the weight and complexity of your architecture, especially at build time.
I can get you halfway there if you are willing to use extension methods. Here's an example:
public static void Bar(this IBob CallingIBob)
{
int Id = CallingIBob.Id;
}
...and calling Bar():
public class Bob : IBob
{
#region IBob Members
public void Foo()
{
this.Bar();
}
public int Id
{
get { throw new NotImplementedException(); }
}
#endregion
}
Yes, it's not the exact case you were looking for, but functionally similar. Bar can be called from any bob and it will have a reference to the calling bob without explicitly passing in the instance.
I understand that you may want to call Bar in another assembly of your choice. Maybe Bar is defined in a base class and you are calling specific implementations of it in subclasses. That's ok, use the extension method to take in information about the specific Bar you are trying to access and route accordingly.
Please update your post with a more concrete problem definition if you would like a more specific solution.
I've defined the following generic class
public class ManagedClass<T> where T : ManagedClass<T>
{
static ManagedClass()
{
Manager = new ObjectManager<T>();
}
public static ObjectManager<T> Manager { get; protected set; }
public ManagedClass()
{
Manager.Add( (T)this );
}
}
The idea is that I can use it like so:
class Product : ManagedClass<Product> {}
Now I can do something to the 7th product created like so:
Product.Manager.GetById(7).DoSomething();
The problem comes in if i try to use a derived class:
class ExtendedProduct : Product {}
now ExtendedProduct.Manager has a list of 'Products', and if i want to use a new function that I have added to ExtendedProduct (DoSomethingElse), I have to cast the object I get back like so:
((ExtendedProduct)ExtendedProduct.Manager.GetById(7)).DoSomethingElse();
This is a bit ugly, and the whole point of using generics for this is to avoid casting. I suppose I could add a static constructor to the derived class to set Manager = new ObjectManager() and add a new Manager.addObject( this ) in the derived class constructor, but It seems like there should be some better way of doing this using generics. Any suggestions?
The problem is that ExtendedProduct.Manager is the same thing as Product.Manager; the manager object can't act differently depending on where it's accessed from.
A couple of possibilities I can think of:
Hide the typecast inside the GetById method by making it generic:
Product.Manager.GetById<ExtendedProduct>(7).DoSomethingElse();
Use one ObjectManager instance per subclass, connecting them privately if needed
Option 1 reminds me of NHibernate's ICriteria interface. It's effectively the same as a typecast, but a little harder to accidentally break.
Really what you're running into is a weakness with Generics. Once your class has resolved what type it's using for generics, you're somewhat restricted in what you can do.
Normally, I'd say Dependency Injection would be a savior here, but since the problematic method is static, that muddies up the waters.
I'd say the best thing is to have the ObjectManager class do the work for you:
static public class ObjectManager<T>
{
... the code that already exists in ObjectManager ...
static public U GetById<U>(long id)
{
object obj = GetById(id);
if (obj is U)
return (U)obj;
return default(U);
}
}
Then, in your code:
ExtendedProduct.Manager.GetById<ExtendedProduct>(7).DoSomethingElse();
It's not really tons more elegant than casting, but may be one of the only solutions using Generics.