Unity Container - Passing in T dynamically to the Resolve method - c#

I've created an ISearchable interface that I've Typed so that I can retrieve an IEnumerable of T for the results.
I have a number of services that implement ISearchable for different domain objects ...
Container.RegisterType<ISearchable<Animal>, AnimalService>();
Container.RegisterType<ISearchable<Fish>, FishService>();
I want to resolve (through Unity) an ISearchable based on the type, but am struggling to get it to work ...
The following dosn't compile but will hopefully give an idea of what I'm trying to achieve.
Type t = typeof(Animal);
var searchProvider = _container.Resolve<ISearchable<t>>();
Any helped gratefully received!
Thanks,
Andy

Finally sorted it, hopefully it'll be of help to someone else!
var type = filter.GetType();
var genericType = typeof(ISearchable<>).MakeGenericType(type);
var searchProvider = _unityContainer.Resolve(genericType);

Why not register your types by name and resolve that way?
Container.RegisterType<ITelescopeView, TelescopeView>("type1");
Container.RegisterType<ITelescopeView, TelescopeView2>("type2");
Container.Resolve(ITelescopeView, "type1");
If you want your names can simply be the type's full name or you could use something else. Dmitri's approach will work too. But this might result in clearer code.

How about...
var sp = container.Resolve(
Type.GetType("ISearchable`1[" + yourGenericTypeHere + "]"));

Related

Getting Items from an Orchard CMS Custom Content Type object

We've created a custom Type in orchard through the Admin page, it has fields on it. How can I get access to those fields in a module?
The way I can find to do it is:
dynamic firstCourse = _contentManager.Query().ForType("Course").List().First();
var fields = firstCourse.Parts[5].Fields as List<ContentField>;
This is can't be the right solution.
dynamic firstCourse = _contentManager.Query("Course").List().First();
var myField = firstCourse.Course.MyField as WhateverTypeTheFieldIs;
This should do the trick to get the field called "MyField" but your question is unclear about what exactly you're trying to do. If you're trying to get the list of all fields, then this should work, I think:
var fields = firstCourse.Course.Fields as IEnumerable<ContentField>;
(also, you are more likely to get a good answer if you don't insult the people most likely to provide it. The documentation is open source, so go and fix it.)

Ninject: Resolve list of all registered types with constructor parameters

I am able to get a list of all the registered types by doing
var myTypes = kernel.Get<List<IMyInterface>>();
The MyType implementations need to take in a constructor argument though. I thought I could accomplish this by doing
kernel.Get<List<IMyInterface>>(
new ConstructorArgument("argName", argValue ) );
but this doesn't seem to work. I get an exception saying it's trying to resolve the parameter "argName" and can't. I'm guessing it's trying to use that arg for the List, and not each type in the list.
Is there a way to do this?
Update:
I'm able to do this in a round about way by doing
var types =
from t in typeof(IMyInterface).Assembly.DefinedTypes
where typeof(IMyInterface).IsAssignableFrom(t)
where t.IsClass
select (IMyInterface)kernel.Get(t,
new ConstructorArgument("argName", argValue));
This is not ideal.
Update:
I ended up changing my class constructor to not take in the parameter. I think it was not a good DI practice the way I had it working.
You can specify constructor arguments in the type Bindings
kernel.Bind<IMyInterface>().To<MyType>().WithConstructorArgument("argName",argValue);
With that binding in place, argValue will be injected into MyType constructor.
UPDATE:
If the argument is known only in runtime, you could do it like this:
In the binding get the value for construtor from request parameters:
kernel.Bind<IMyInterface>().To<MyType>().WithConstructorArgument("argName",
r => r.Parameters.First().GetValue(r.Request.ParentContext, r.Request.Target));
When creating instance, pass the parameter into request:
kernel.Get<List<IMyInterface>>( new Ninject.Parameters.Parameter("argName",argValue) );
If you want all registered types you should use GetAll<T> instead of Get<List<T>>:
kernel.GetAll<IMyInterface>(new ConstructorArgument("argName",argValue));
you can materialize that as a list if you really need to using LINQ's ToList.

Get Generic Container Type

I need to find out if a Type I'm working with is a Generic 'container', for example if I have a List<int> I need to check if I'm working with a List (I know how to get whether I'm working with an int), how would I do that? (I'm thinking Reflection). Another example, I have a class called StructContainer<T>, I need to find the word (name) 'StructContainer', I'm not too bothered with what 'T' is, using reflection I get StructContainer'1, would hate to have to do some string splitting etc /EDIT: Just to explain further, StructContainer<int> I need 'StructContainer', Tuple<int> I need 'Tuple', List<int> I need 'List' and so forth
Your first question can be achieved in multiple ways:
Check whether your object implements IEnumerable<T>: yourObject is IEnumerable<int>. This only works if you know the type of the object in the container (int in this case)
Use the same solution I described below, just change StructContainer to List.
As to your second question, you can do this:
var yourObject = new StructContainer<int>();
var yourType = yourObject.GetType();
if(yourType.IsGenericType &&
yourType.GetGenericTypeDefinition() == typeof(StructContainer<>))
// ...
string type = yourObject.GetType().Name.Split('`')[0];

IOC Container Runtime Resolution

I'm trying to find an IOC container that will allow me to have mapping data for a field stored in a database and resolve the interface or object that needs resolved via a string value pulled from the database.
Most of the examples I have seen are using interfaces hard coded in code, I want the interface that needs to be resolved to be dynamic.
This is what I usually see:
var taskController = container.Resolve<ITaskController>();
This is what I would like to see:
var strTaskController = "ITaskController";
var taskController = container.Resolve(strTaskController);
I'm sure I could look through the documentation for all the IOC containers but I am hoping this is an easy question for someone with more IOC experience.
Using Unity you can do what you're looking for. Basically, if you know the full type name, you can do this first:
var type = Type.GetType("Fully.Qualified.Type.Name");
var resolvedInstance = container.Resolve(type);
EDIT: Based on the comment, here's another approach:
string typeName = "MyTypeName";
var type = container.Registrations.FirstOrDefault(r => r.RegisteredType.Name == typeName);
if(type != null)
{
var resolvedInstance = container.Resolve(type.RegisteredType);
}
I think this is the answer I am going with..
Managed Extensibility Framework
http://msdn.microsoft.com/en-us/library/dd460648.aspx
Got to love it when you find a new framework to find the exact solution to your problem.
You can use the IOC container from the Castle project.

Can I start with a string and instantiate an object of that string?

I am currently working with LINQ and C#.
I have a DropDownList of the tables in my LINQ to SQL model.
I want the user to be able to select a LINQ table name from the DropDown. In code I want to create an instance of that LINQ class and then run a Select or it or anything else I want.
How would I accomplish creating the object based on what object name in string the user chose? Am I thinking incorrectly from the start?
You want Type.GetType(string) and Activator.CreateInstance(Type).
Note that Type.GetType(string) will only look in the currently executing assembly and mscorlib unless you specify the full type name including assembly. In either case, you need to specify the type name including namespace.
Another alternative is to use Assembly.GetType(string) to get the type directly from the string before calling Activator.CreateInstance.
(There are actually lots of alternatives here. If none of these help you, please post more info and I'm sure we can work out a way to go.)
Since you tagged the post with ASP.NET, I am assuming that the list is on the client side. If that is the case, you should be very careful about trusting that data, and I would not recommend creating types directly from user input. You could use the data as input to a factory that could then return the proper instance (and handle any illegal input as you see fit).
Elaborating on Brian Rasmussen's warning: The types should be restricted and require conscious design. Preferable the "user-instantiable" types should be marked with a specific custom attribute that can be verified with reflection.
With LINQ-to-SQL, there are specific ways of doing this from the data-context; basically, db.GetTable. This returns an ITable, but it is a little tricky to work with an untyped ITable. You can enumerate it, at least...
To get the ITable, you normally need the Type, which you can get with (for example) Assembly.GetType:
using (var ctx = new MyDataContext()) {
string name = "Customer"; // type name
Type ctxType = ctx.GetType();
Type type = ctxType.Assembly.GetType(
ctxType.Namespace + "." + name);
ITable table = ctx.GetTable(type);
foreach(var row in table) {
Console.WriteLine(row); // works best if ToString overridden...
}
}
Of course, once you have the Type, you use use Activator to create new entity instances:
object newObj = Activator.CreateInstance(type);
// TODO: set properties (with reflection?)
table.InsertOnSubmit(newObj);
but if you want to use the property-name, that can work too:
using (var ctx = new MyDataContext()) {
string name = "Customers"; // property name
ITable table = (ITable) ctx.GetType()
.GetProperty(name).GetValue(ctx, null);
foreach (var row in table) {
Console.WriteLine(row); // works best if ToString overridden...
}
}
Running filters (Where) etc is tricky with untyped data, as building the Expression would be tortuous. I'd probably start switching to a typed model at that point...
To follow on Marc Gravell's answer.
Doing as he suggested, I noticed a Cast<TResult> extension method (defined in System.Linq).
Unfortunately you can't seem to be able to do use the type instance to cast:
Type dcType = dc.GetType();
Type type = dcType.Assembly.GetType(String.Format("{0}.{1}", dcType.Namespace, name));
var row = dc.GetTable(type).Cast<type>().SingleOrDefault(i => i.ID == 123);

Categories