How to put an interface in a generic dynamically? - c#

I have the following test class:
public class OutsideClass
{
private List<Type> _interfaces = null;
public void InjectInterfaces(Type[] types)
{
if(_interfaces == null)
{
_interfaces = new List<Type>();
}
foreach (var type in types)
{
if(type.IsInterface)
{
_interfaces.Add(type);
}
}
}
public void PerformSomethingWithTheInterfaces()
{
foreach (var i in _interfaces)
{
new Test<i>().PerformSomething(); // On this line the error occurs
}
}
}
internal class Test<T>
{
internal void PerformSomething()
{
}
}
This gives me on however the message Type or namespace name expected. How can I adjust this code so that it works?
What I am trying to do is to pass in a bunch of interfaces to a class library, there loop over the interfaces and use Unity to Resolve, based on the interface, something. I use the Resolve extension method.

You'd need to use reflection... something like this:
foreach (Type type in _interfaces)
{
Type concreteType = typeof(Test<>).MakeGenericType(new Type[] { type });
MethodInfo method = concreteType.GetMethod("PerformSomething",
BindingFlags.Instance | BindingFlags.NonPublic);
object instance = Activator.CreateInstance(concreteType);
method.Invoke(instance, null);
}
(You may need to make minor changes - the above isn't tested or even compiled.)
With C# 4 and dynamic typing, you can make it somewhat simpler:
foreach (Type type in _interfaces)
{
Type concreteType = typeof(Test<>).MakeGenericType(new Type[] { type });
dynamic d = Activator.CreateInstance(concreteType);
d.PerformSomething();
}

You cannot pass values as generic arguments. Only types. To be clear:
typeof(string) != string.

I don't think this can work. You specialize a generic statically on the type name. You can't pass in a reference to the Type object.
There are ways to do what you want, but they involve C# 4 and DynamicObject.

You might really want to look at C# 4's MEF just as an idea as a unity replacement I think it stands up really well myself and simplifies the resolution mechanisms a lot, and may give functionality to complete the task you're attempting more simply..
namespace MEF_Interface
{
// Interface to recognize the concrete implementation as
public interface IMessageWriter
{
void WriteMessage();
}
}
namespace MEF_HelloMessageWriter
{
// Concrete implementation in another assembly
[Export(typeof(IMessageWriter))]
public class HelloMessageWriter : IMessageWriter
{
public void WriteMessage() { Console.WriteLine("Hello!"); }
}
}
namespace MEF_GoodbyeMessageWriter
{
// Concrete implementation in another assembly
[Export(typeof(IMessageWriter))]
public class GoodbyeMessageWriter : IMessageWriter
{
public void WriteMessage() { Console.WriteLine("Goodbye!"); }
}
}
namespace MEF_Example
{
class DIContainer
{
[Import]
public IMessageWriter MessageWriter { get; set; }
public DIContainer(string directory)
{
// No more messy XML DI definition, just a catalog that loads
// all exports in a specified directory. Filtering is also available.
DirectoryCatalog catalog = new DirectoryCatalog(directory);
catalog.Refresh();
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
class Program
{
static void Main(string[] args)
{
string helloMessageWriterPath =
#"C:\shared\Projects\MEF_Example\MEF_HelloMessageWriter\bin\Debug";
string goodbyeMessageWriterPath =
#"C:\shared\Projects\MEF_Example\MEF_GoodbyeMessageWriter\bin\Debug";
DIContainer diHelloContainer = new DIContainer(helloMessageWriterPath);
diHelloContainer.MessageWriter.WriteMessage();
DIContainer diGoodbyeContainer = new DIContainer(goodbyeMessageWriterPath);
diGoodbyeContainer.MessageWriter.WriteMessage();
Console.ReadLine();
}
}
}

Related

c# Converting a type to a generic

I'm trying to consolidate some code in an old .NET 4.0 project using UnityContainer for DI.
I have the following list of registrations, which are lazy loaded, with a constructor injection in a Unity registry:
public class MyRegistry : UnityRegistry
{
public MyRegistry()
{
Register(GetDataAccessInjectionFactory<AddressProviderBase>());
Register(GetDataAccessInjectionFactory<CustomerProviderBase>());
// Hundreds of these registrations..... manually maintained... urrgh
// I want to scan for them instead
}
private Func<IUnityContainer, T> GetDataAccessInjectionFactory<T>() where T : class
{
return c => DataAccessProvider<T>.GetDataAccess(c.Resolve<ITenantCodeProvider>());
}
}
The DataAccessProvider is just a cached concurrent dictionary in order to switch database connection based on the tenant. It looks like this:
public class DataAccessProvider<T> where T : class
{
public static T GetDataAccess(ITenantCodeProvider tenantCodeProvider)
{
// ... implementation
}
}
I'm trying to replace them with a single UnityContainer scan using a custom convention:
Scan(scan =>
{
scan.With<CustomProviderBaseConvention>();
scan.AssemblyContaining<AddressProviderBase>();
});
However, the IAssemblyScannerConvention interface provides me with this:
public class CustomProviderBasesConvention : IAssemblyScannerConvention
{
// required interface
void IAssemblyScannerConvention.Process(Type type, IUnityRegistry registry)
{
// this "type" obviously won't work. Do I need reflection here?
registry.Register(GetDataAccessInjectionFactory<type>());
}
public Func<IUnityContainer, T> GetDataAccessInjectionFactory<T>() where T : class
{
return c => DataAccessProvider<T>.GetDataAccess(c.Resolve<ITenantCodeProvider>());
}
}
This is more of a generics / typing issue than something to do with Unity DI. Any pointers about how to replace the hundreds of manually added and maintained ProviderBase registrations would be most welcomed.
Even using reflection, I end up with the same problem, that I can't cast the result:
public class CustomProviderBasesConvention : IAssemblyScannerConvention
{
void IAssemblyScannerConvention.Process(Type type, IUnityRegistry registry)
{
MethodInfo method = typeof(DataAccessProvider<>).GetMethod("GetDataAccess", BindingFlags.Public | BindingFlags.Instance);
MethodInfo generic = method.MakeGenericMethod(type);
// cast needs a type
var factory = (Func<IUnityContainer, ????>)generic.Invoke(this, null);
registry.Register(factory);
}
public Func<IUnityContainer, T> GetDataAccessInjectionFactory<T>() where T : class
{
return c => DataAccessProvider<T>.GetDataAccess(c.Resolve<ITenantCodeProvider>());
}
}
I have the same problem if I loop through the assembly types:
var assembly = typeof(AddressProviderBase).Assembly;
var types = assembly.GetTypes().Where(x => x.FullName.EndsWith("ProviderBase")).ToList();
foreach(var t in types)
{
MethodInfo method = typeof(DataAccessProvider<>).GetMethod("GetDataAccess", BindingFlags.Public | BindingFlags.Instance);
MethodInfo generic = method.MakeGenericMethod(t);
Register((Func<IUnityContainer, ??>)generic.Invoke(this, null));
}
The Unity itself may have the better way to do this, but if we want to go in the reflection way, then we can do the following.
public class CustomProviderBasesConvention : IAssemblyScannerConvention
{
void IAssemblyScannerConvention.Process(Type type, IUnityRegistry registry)
{
var method = typeof(CustomProviderBasesConvention).GetMethod(nameof(Helper),
BindingFlags.Instance | BindingFlags.NonPublic);
var generic = method.MakeGenericMethod(type);
generic.Invoke(this, new[] { registry });
}
private void Helper<T>(IUnityRegistry registry) where T : class
{
var factory = GetDataAccessInjectionFactory<T>();
registry.Register(factory);
}
public Func<IUnityContainer, T> GetDataAccessInjectionFactory<T>() where T : class
{
return c => DataAccessProvider<T>.GetDataAccess(c.Resolve<ITenantCodeProvider>());
}
}
The problem in the assemble scan code may be solved with exactly the same way with generic Helper function.

getting the property type in a generic class (Mono.Cecil)

I am using Mono.Cecil to automatically generate (lots of, simple, generic) factory methods providing a convenient API for a library. The factories are generated for properties marked with a special custom attribute. To generate them, I must know the type of such property. The non-generic case is simple:
ModuleDefinition module = /* obtained from ReadAssembly */
foreach (var type in module.Types)
if (/* type is marked with the right attribute */)
foreach (var prop in type.Properties)
if (/* prop is marked with the right attribute */)
GenerateFactory(type, prop, prop.PropertyType);
However, some of the types marked are in fact generics. In this case, the attribute on the type contains the generic arguments for which the factory should be made, like this:
[EmitFactories(typeof(int))]
public class Class<T>
{
[MagicProperty]
T Property { get; set; }
}
(here, I want the factory to be made for Class<int>.Property).
I am handling this case by making type a GenericInstanceType. However, I cannot get to the type of the property -- to enumerate type.Properties I need to first call Resolve(), which loses all generic information. The property type is then T (instead of int), which of course makes later code fail miserably.
Mono.Cecil has GenericInstanceType and GenericInstanceMethod, but there is no equivalent for properties. I tried using module.Import(prop.PropertyType, type) (giving type as the generic parameter provider), but this doesn't work.
Do you have any ideas on how I can resolve the actual property type? Note, that it can be completely unrelated to T, T itself, or have T burried inside (e.g., List<T>). Ideally, it would work given type as a TypeReference -- this way I would not have to write separate code for the non-generic and generic cases.
Based on https://stackoverflow.com/a/16433452/613130, that is probably based on https://groups.google.com/d/msg/mono-cecil/QljtFf_eN5I/YxqLAk5lh_cJ, it should be:
using System;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Rocks;
namespace Utilities
{
public class EmitFactoriesAttribute : Attribute
{
public readonly Type[] Types;
public EmitFactoriesAttribute()
{
}
public EmitFactoriesAttribute(params Type[] types)
{
Types = types;
}
}
public class MagicPropertyAttribute : Attribute
{
}
public static class EmitFactories
{
public static void WorkOnAssembly(string path)
{
AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly("ConsoleApplication4.exe");
ModuleDefinition module = assembly.MainModule;
TypeDefinition emitFactoriesAttribute = module.Import(typeof(EmitFactoriesAttribute)).Resolve();
TypeDefinition magicPropertyAttribute = module.Import(typeof(MagicPropertyAttribute)).Resolve();
foreach (TypeDefinition type in module.Types)
{
CustomAttribute emitFactory = type.CustomAttributes.SingleOrDefault(x => x.AttributeType.MetadataToken == emitFactoriesAttribute.MetadataToken);
if (emitFactory == null)
{
continue;
}
TypeReference typeRef = type;
TypeReference[] replacementTypes;
if (emitFactory.ConstructorArguments.Count != 0)
{
var temp = ((CustomAttributeArgument[])emitFactory.ConstructorArguments[0].Value);
replacementTypes = Array.ConvertAll(temp, x => (TypeReference)x.Value);
}
else
{
replacementTypes = new TypeReference[0];
}
if (replacementTypes.Length != type.GenericParameters.Count)
{
throw new NotSupportedException();
}
if (replacementTypes.Length != 0)
{
typeRef = typeRef.MakeGenericInstanceType(replacementTypes);
}
foreach (PropertyDefinition prop in type.Properties)
{
CustomAttribute magicProperty = prop.CustomAttributes.SingleOrDefault(x => x.AttributeType.MetadataToken == magicPropertyAttribute.MetadataToken);
if (magicProperty == null)
{
continue;
}
MethodReference getter = prop.GetMethod;
MethodReference setter = prop.SetMethod;
if (replacementTypes.Length != 0)
{
if (getter != null)
{
getter = getter.MakeHostInstanceGeneric(replacementTypes);
}
if (setter != null)
{
setter = setter.MakeHostInstanceGeneric(replacementTypes);
}
}
}
}
}
}
public static class TypeReferenceExtensions
{
// https://stackoverflow.com/a/16433452/613130
public static MethodReference MakeHostInstanceGeneric(this MethodReference self, params TypeReference[] arguments)
{
var reference = new MethodReference(self.Name, self.ReturnType, self.DeclaringType.MakeGenericInstanceType(arguments))
{
HasThis = self.HasThis,
ExplicitThis = self.ExplicitThis,
CallingConvention = self.CallingConvention
};
foreach (var parameter in self.Parameters)
reference.Parameters.Add(new ParameterDefinition(parameter.ParameterType));
foreach (var generic_parameter in self.GenericParameters)
reference.GenericParameters.Add(new GenericParameter(generic_parameter.Name, reference));
return reference;
}
}
// Test
[EmitFactories(typeof(int), typeof(long))]
public class Class<TKey, TValue>
{
[MagicProperty]
Dictionary<TKey, TValue> Property1 { get; set; }
[MagicProperty]
List<TValue> Property2 { get; set; }
}
}
You hadn't defined how EmitFactoriesAttribute was, so I have written it as a EmitFactoriesAttribute(params Type[] types), to be able to accept multiple substitutions for cases like Class<TKey, TValue>.
In the end I'm not manipulating directly the property: I'm manipulating its getter and setter.
I'm not able to test it, because I don't have the factory...

How can I use reflection to pass each list of "MyTypes" to a generic method with a constraint of T:MyType?

How can I use reflection to pass each list of "MyTypes" to a generic method with a constraint of T:MyDataObject?
public interface IAllMyTypes
{
List<FirstType> MyType1 { get; set; }
List<SecondType> MyType2 { get; set; }
List<ThirdType> MyType3 { get; set; }
}
FirstType, SecondType, and ThirdType inherit from MyDataObject (as demonstrated below), but have different properties.
public class FirstType : MyDataObject
{
//various properties
}
I've been unable to pass the data into a method with this signature:
void DoSomething<T>(IEnumerable<T> enumerable) where T : MyDataObject;
The error is that "type arguments can not be inferred."
Here is my unsuccessful attempt:
public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
foreach (PropertyInfo propertyInfo in allMyTypes.GetType().GetProperties())
{
var x = propertyInfo.GetValue(allMyTypes) as IList;//im not sure what to do here
if(x==null) throw new Exception("still wrong");
DoSomething(x);
}
}
All of the code in DoSomething(..) works correctly if I provide the properties directly which looks like:
public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
DoSomething(allMyTypes.MyType1);
DoSomething(allMyTypes.MyType2);
DoSomething(allMyTypes.MyType3);
}
If you want to use reflection, you can invoke your helper method using reflection, too:
You will have to obtain a MethodInfo to a generic method and create a generic method reflection handle to actually Invoke the method. The type T of the generic method needs to be obtained at runtime in that case.
public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
var method = this.GetType().GetMethod("DoSomething", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo propertyInfo in allMyTypes.GetType().GetProperties())
{
var x = propertyInfo.GetValue(allMyTypes, null);
if(x==null) throw new Exception("still wrong");
// obtain the type from the property - other techniques can be used here.
var genericMethod = method.MakeGenericMethod(new[] {propertyInfo.PropertyType.GetGenericArguments()[0]})
//execute the generic helper
genericMethod.Invoke(this, new[]{x});
}
}
public void DoSomething<T>(IList<T> list) where T : MyDataObject {
}
I'm struggling to find a case where you'd need to structure your data the way you did without over-complicating things. If you've found a legit case please comment and I'll update my answer to reflect your needs.
You can start with your base class, make it abstract and put an abstract method in it DoSomething
public abstract class MyDataObject{
public string SomeSharedProperty{get;set;}
protected abstract DoSomething();
}
public class FirstType: MyDataObject{
protected override DoSomething(){
Console.WriteLine(SomeSharedProperty);
}
}
public class Consumer{
public void DoSomethingWithAllMyTypes(List<MyDataObject> source)
{
source.ForEach(x=>x.DoSomething());
}
}
You could use the Linq method call Cast<T> to convert your list to the right type
public void DoSomethingWithAllMyTypes(IAllMyTypes allMyTypes)
{
foreach (PropertyInfo propertyInfo in allMyTypes.GetType().GetProperties())
{
var x = propertyInfo.GetValue(allMyTypes) as IEnumerable
if(x==null) throw new Exception("still wrong");
DoSomething(x.Cast<MyDataObject>());
}
}

How to get the concrete implementation of an interface by the generic type?

I need some help figure out how to use reflection to get the concrete implementation based of the Dto type:
public interface IDocumentService<TDto>
{
}
public interface ICommentService: IDoumentService<CommentDto>
{
}
public abstract class DocumentService<TEntity,TDto>: IDocumentService<TDto> where TEntity: Entity, where TDto: Dto
{
}
public class CommentService: DocumentService<Comment,CommentDto>, ICommentService
{
}
So, what I want to do, is pass the CommentDto to a method so I can get to the CommentService.
public IDocumentService<TDto> GetDocumentService<TDto>()
{
//based on the TDto type I want to find the concrete that
//implements IDocumentService<TDto>
}
I would call it like this:
var commentDocumentService = GetDocumentService<CommentDto>();
So, I would get back CommentService, knowing that I would only see the methods part of the IDocumentService interface.
Here is a possible implementation for GetDocumentService.
public static IDocumentService<TDto> GetDocumentService<TDto>()
{
// Gets the type for IDocumentService
Type tDto=typeof(IDocumentService<TDto>);
Type tConcrete=null;
foreach(Type t in Assembly.GetExecutingAssembly().GetTypes()){
// Find a type that implements tDto and is concrete.
// Assumes that the type is found in the executing assembly.
if(tDto.IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface){
tConcrete=t;
break;
}
}
// Create an instance of the concrete type
object o=Activator.CreateInstance(tConcrete);
return (IDocumentService<TDto>)o;
}
It wasn't clear whether you wanted to return a new object, so I assumed so.
EDIT:
Due to your comment, here is a modified version of GetDocumentService. The disadvantage is that you need to specify another type parameter. The advantage, though, is that this approach provides a certain degree of type safety, since both type parameters must be compatible.
public static T GetDocumentService<TDto, T>() where T : IDocumentService<TDto>
{
// Gets the type for IDocumentService
Type tDto=typeof(T);
Type tConcrete=null;
foreach(Type t in Assembly.GetExecutingAssembly().GetTypes()){
// Find a type that implements tDto and is concrete.
// Assumes that the type is found in the calling assembly.
if(tDto.IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface){
tConcrete=t;
break;
}
}
// Create an instance of the concrete type
object o=Activator.CreateInstance(tConcrete);
return (T)o;
}
EDIT 2:
If I understand correctly, you want to get the other interfaces implemented by the type of the return value of GetDocumentService. For example, GetDocumentService<CommentDto> returns an object of type CommentService that implements the ICommentService interface. If I understand correctly, the return value should be a Type object (for example, the return value could be typeof(ICommentService)). Once you have the type, you should call the type's FullName property to get the type's name.
Use the following method on the return value of GetDocumentService to get the type of interface implemented by that value, for instance, typeof(ICommentService).
public static Type GetDocumentServiceType<TDto>(IDocumentService<TDto> obj){
Type tDto=typeof(IDocumentService<TDto>);
foreach(Type iface in obj.GetType().GetInterfaces()){
if(tDto.IsAssignableFrom(iface) && !iface.Equals(tDto)){
return iface;
}
}
return null;
}
Firstly, your CommentService class needs to be discoverable somehow, given the type of TDto. You can search all the loaded types from all the assemblies in the current AppDomain - however that will be painfully slow.
So you have the following viable options:
Use an attribute on the assembly that defines CommentService.
Use configuration to define this information.
Use MEF.
I'll demonstrate the first approach. Firstly create the attribute:
[AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = true)]
public sealed class DtoProviderAttribute : Attribute
{
public Type ProvidedType { get; private set; }
public Type ProviderType { get; private set; }
public DtoProviderAttribute(Type providedType, Type providerType)
{
ProvidedType = providedType;
ProviderType = providerType;
}
}
And then apply it to the assembly that defines CommentService (typically you would put in AssemblyInfo.cs).
[assembly:DtoProvider(typeof(CommentDto), typeof(CommentService))]
Now you can use those attributes to search for the concrete implementations.
public class ServiceFactory
{
private static readonly Dictionary<RuntimeTypeHandle, Func<object>> _dtoMappings = new Dictionary<RuntimeTypeHandle, Func<object>>();
public static IDocumentService<TDto> GetDocumentService<TDto>()
{
var rth = typeof(TDto).TypeHandle;
Func<object> concreteFactory;
lock (_dtoMappings)
{
if (_dtoMappings.TryGetValue(typeof(TDto).TypeHandle, out concreteFactory))
return (IDocumentService<TDto>)concreteFactory();
FillMappings();
if (!_dtoMappings.TryGetValue(typeof(TDto).TypeHandle, out concreteFactory))
throw new Exception("No concrete implementation found.");
return (IDocumentService<TDto>)concreteFactory();
}
}
private static void FillMappings()
{
// You would only need to change this method if you used the configuration-based approach.
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var attrs = assembly.GetCustomAttributes(typeof(DtoProviderAttribute), false);
foreach (DtoProviderAttribute item in attrs)
{
if (!_dtoMappings.ContainsKey(item.ProvidedType.TypeHandle))
{
var expr = Expression.Lambda<Func<object>>(Expression.Convert(Expression.New(item.ProviderType), typeof(object)));
_dtoMappings.Add(item.ProvidedType.TypeHandle, expr.Compile());
}
}
}
}
}
As 'Rune' pointed out: because of the cache the overhead of searching all the assemblies is low:
private static void FillMappings()
{
foreach (var type in AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).Where(x => x.IsClass && !x.IsAbstract))
{
foreach (var iface in type.GetInterfaces().Where(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDocumentService<>)))
{
var arg = iface.GetGenericArguments()[0];
if (!_dtoMappings.ContainsKey(arg.TypeHandle))
{
var expr = Expression.Lambda<Func<object>>(Expression.Convert(Expression.New(type), typeof(object)));
_dtoMappings.Add(arg.TypeHandle, expr.Compile());
}
}
}
}
another possibility:
public IDocumentService<TDto> GetDocumentService<TDto>()
{
var genericParameter = typeof(TDto);
return (from type in Assembly.GetExecutingAssembly().GetTypes() // Get Types
where type.GetConstructor(Type.EmptyTypes) != null // That is concrete
let interfaces = type.GetInterfaces()
from intf in interfaces
where intf.IsGenericType // Which implement generic interface
let genarg = intf.GetGenericArguments()[0]
where genarg == genericParameter // Where generic argument is of type genericParameter
select (IDocumentService<TDto>) // Cast to IDocumentService
Activator.CreateInstance(type)).FirstOrDefault(); // Instantiate
}

Failing to create type dynamically

I am trying to come up with a method factory that looks inside config to get the full name of the type to instantiate and creates that object type dynamically.
Here is my Type and the Interface:
public interface IComponent<T>
{
IEnumerable<T> DataSource {get; set;}
void PerformTask(object executionContext);
}
namespace MyCompany.Components
{
public class ConcreteComponent1<T> : IComponent<T>
{
private IEnumerable<Contact> contactSource = null;
internal ConcreteComponent1() {}
public void PerformTask(object executionContext)
{
this.contactSource = GetSource(executionContext);
foreach(var result in this.contactSource)
{
result.Execute(executionContext);
}
}
public IEnumerable<T> DataSource
{
get { return this.contactSource as IEnumerable<T>; }
set { this.contactSource = (IContactSource)value; }
}
}
}
Factory, resides in the same assembly:
//Factory - Same assembly
public static class ComponentFactory<T>
{
public static IComponent<T> CreateComponent()
{
var assembly = Assembly.GetExecutingAssembly();
object o = assembly.CreateInstance("MyCompany.Components.ConcreteComponent1"); //o is null...
var objectHandle = Activator.CreateInstance(Assembly.GetAssembl(typeof(ComponentFactory<T>)).GetName().FullName, "MyCompany.Components.ConcreteComponent1"); //throws Could not load type from assembly exception.
return o as IComponent<T>;
}
}
So in first case the o is always null.
In the second case when using the Activator class, it throws Type could not be loaded from assembly "MyAssembly". No inner exception. What am I doing wrong?
First of all, actual name of your type is:
MyCompany.Components.ConcreteComponent1`1
It can't be instantiated because you have to specify type parameters:
public static class ComponentFactory<T>
{
public static IComponent<T> CreateComponent()
{
Type generic = Type.GetType("MyCompany.Components.ConcreteComponent1`1");
Type concrete = generic.MakeGenericType(typeof(T));
var objectHandle = Activator.CreateInstance(
concrete,
BindingFlags.NonPublic | BindingFlags.Instance,
null,
null, //here can come ctor params
null);
return objectHandle as IComponent<T>;
}
}
this will work with internal constructor.
I'd say the actual name of your class ConcreteComponent1 is not "MyCompany.Components.ConcreteComponent1" because it includes a generic. Execute
Console.WriteLine(typeof(ConcreteComponent1<T>).FullName);
to see the string representation for your class created by C#.
But why do you define your ConcreteComponent1 class the way you do? Wouldn't it be better to use something like this:
public class ConcreteComponent1 : IComponent<Contact> {
internal ConcreteComponent1() {}
public void PerformTask(object executionContext)
{
this.contactSource = GetSource(executionContext);
foreach(var result in this.contactSource)
{
result.Execute(executionContext);
}
}
public IEnumerable<Contact> DataSource
{
get { return this.contactSource; }
set { this.contactSource = value; }
}
}
This way you can use the expected name you already used in your example and you can remove the extra private field your approach introduces. As your ConcreteComponent1 class doesn't really need any generic functionality this would be a better approach in my opinion.

Categories

Resources