Unity 3.5: Retrieve concrete implementation by its open generic interface - c#

This blog post describes a nice alternative to the Repository pattern.
https://cuttingedge.it/blogs/steven/pivot/entry.php?id=92
Instead of Repositories the author recommends the use of Commands and Queries. The particular blog post describes the implementation of the Query part in .NET/C#.
There are two interfaces for the query and for the query handler:
public interface IQuery<TResult>
{
}
public interface IQueryHandler<TQuery, TResult> where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}
He also offers an example for each:
public class FindUsersBySearchTextQuery : IQuery<User[]>
{
public string SearchText { get; set; }
public bool IncludeInactiveUsers { get; set; }
}
public class FindUsersBySearchTextQueryHandler
: IQueryHandler<FindUsersBySearchTextQuery, User[]>
{
private readonly NorthwindUnitOfWork db;
public FindUsersBySearchTextQueryHandler(NorthwindUnitOfWork db)
{
this.db = db;
}
public User[] Handle(FindUsersBySearchTextQuery query)
{
return (
from user in this.db.Users
where user.Name.Contains(query.SearchText)
select user)
.ToArray();
}
}
The query handler can be provided as a constructor parameter to a MVC controller.
public class UserController : Controller
{
IQueryHandler<FindUsersBySearchTextQuery, User[]> handler;
public UserController(IQueryHandler<FindUsersBySearchTextQuery, User[]> handler)
{
this.handler = handler;
}
public View SearchUsers(string searchString)
{
var query = new FindUsersBySearchTextQuery
{
SearchText = searchString,
IncludeInactiveUsers = false
};
User[] users = this.handler.Handle(query);
return this.View(users);
}
}
The author uses the dependency injection container Simple Injector to register all IQueryHandler's at once:
container.RegisterManyForOpenGeneric(
typeof(IQueryHandler<,>),
typeof(IQueryHandler<,>).Assembly);
My question is: How can I do this last statement in Unity?
I'm using Unity 3.5.
I'm able to register each QueryHandler manually, like this:
container.RegisterType<IQueryHandler<FindUsersBySearchTextQuery, User[]>,
FindUsersBySearchTextQueryHandler>();
This works fine but I don't want to add a new mapping each time a new QueryHandler comes up. I want to set up all mappings with one convention which includes future QueryHandler's. Unity 3.5 offers a convention based registration workflow but I could not make it work for my case. I tried this but unfortunately it does not generate the mappings in question.
container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMappings.FromMatchingInterface,
WithName.Default);

If you are going to have many specific implementations of IQueryHandler<,> and not one generic version, then you can't use open generics to register. But you can use reflection to find all implementations and register them each. (This is what RegisterTypes does behind the scenes for you).
You were close with your attempt at the RegisterTypes call in the question, but you used WithMappings.FromMatchingInterface. This will only register classes with their interface that matches by the naming convention of MyClass : IMyClass (prepending an 'I' to the class name). If you instead register with WithMappings.FromAllInterfaces you will get the registrations you are after.
container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMappings.FromAllInterfaces,
WithName.Default);
If you need to only register those classes, you can filter down the classes to only those that implement the interface you are after...
public static class EnumerableTypeExtensions
{
public static IEnumerable<Type> WhichImplementsInterface<T>
(this IEnumerable<Type> types)
{
return types.WhichImplementsInterface(typeof (T));
}
public static IEnumerable<Type> WhichImplementsInterface
(this IEnumerable<Type> types, Type interfaceType)
{
return types.WhichImplementsInterface(interfaceType.Name);
}
public static IEnumerable<Type> WhichImplementsInterface
(this IEnumerable<Type> types, string interfaceTypeName)
{
return types.Where(t => t.GetInterface(interfaceTypeName) != null);
}
}
Then you can use these filters like this...
container.RegisterTypes(
AllClasses.FromLoadedAssemblies().WhichImplementsInterface(typeof(IQueryHandler<,>)),
WithMappings.FromAllInterfaces,
WithName.Default);

Related

How to create generic mapper like this?

I have many classes, that have similar operations of mapping objects. To keep code dry I want to create base abstract class for all these classes.
base abstract class would have generic mapping function like this:
public TEntity GetEntity(Result<TServiceClientEntity> res)
{
entity = MappingProfiles.TryMap(res.Value);
//some logic with result here
return entity;
}
Result class:
public class Result<T>
{
public T Value{ get; set; }
//some more properties..
}
But the problem is that I can't think a way of how to map generic classes like that:
public static class MappingProfiles
{
public static T2 TryMap<T,T2>(T t)
{
return (T2)Map((Real_T_type)t); //f.e.: the type is ExampleFrom
}
public static ExampleTo Map(ExampleFrom from)
{
return new ExampleTo
{
exapleValue = from.exapleValue
};
}
}
EDIT:
I also want that TryMap generic method use my predefined Map manual methods for mapping.
You can use Reflection (C#) to accomplish such things:
public static TOut Map<TIn, TOut>(TIn source)
where TOut : new()
{
var inPropDict = typeof(TIn).GetProperties()
.Where(p => p.CanRead)
.ToDictionary(p => p.Name);
var outProps = typeof(TOut).GetProperties()
.Where(p => p.CanWrite);
var destination = new TOut();
foreach (var outProp in outProps) {
if (inPropDict.TryGetValue(outProp.Name, out var inProp)) {
object sourceValue = inProp.GetValue(source);
if (inProp.PropertyType != outProp.PropertyType) {
sourceValue = Convert.ChangeType(sourceValue, outProp.PropertyType);
}
outProp.SetValue(destination, sourceValue);
}
}
return destination;
}
Reflection enables you to inspect a type and to get its properties, fields, etc.
Type.GetProperties() returns an array of PropertyInfo with name, type, and other information about a property. It also allows you to read from or to write to a property of an object.
The code above is just a quick and dirty example without exception handling. It does only a flat mapping and does not map collections or nested objects.
It also could be improved by allowing you to declare mappings for properties not having the same name etc.
There is a tool doing all these things and more called AutoMapper.
Solution with manual mapping methods
I suggest defining an interface like this
public interface IMapper<T1, T2>
{
T2 Map(T1 input);
}
Example of a concrete implementation:
public class ExampleFromToMapper : IMapper<ExampleFrom, ExampleTo>
{
public ExampleTo Map(ExampleFrom input)
{
return new ExampleTo {
ExampleValue = input.ExampleValue
};
}
}
The idea is to use dependency injection to do the job of selecting the right mapper.
You can use the NuGet package Microsoft.Extensions.DependencyInjection as an example. But many other dependency injection frameworks exist.
Write a method configuring the mappers (as extension method in this example):
public static IServiceCollection AddMappers(this IServiceCollection services)
{
return services
.AddSingleton<IMapper<ExampleFrom, ExampleTo>, ExampleFromToMapper>()
.AddSingleton<IMapper<OtherFrom, OtherTo>, OtherFromToMapper>();
}
Define the container somewhere:
public static class Config
{
public static ServiceProvider Container { get; set; }
}
And at startup of your application configure the container
var services = new ServiceCollection();
services
.AddMappers()
.AddTransient<MyForm>(); // See below
Config.Container = services.BuildServiceProvider();
As an example, let us assume that you have a WinForms app with a form defined like this (it uses a mapper directly, but instead it could use other services that do use mappers. The DI container resolves the dependencies recursively and injects them in the constructors automatically):
public partial class MyForm : Form
{
private readonly IMapper<ExampleFrom, ExampleTo> _mapper;
public MyForm(IMapper<ExampleFrom, ExampleTo> mapper)
{
_mapper = mapper;
InitializeComponent();
}
}
Now, you can start the application like this:
var frm = Config.Container.GetRequiredService<MyForm>();
Application.Run(frm);
Okay, at the beginning it looks complicated, but once you have set up the basics it becomes easy to add new services. Every class offering some functionality is considered a service.
Solution with manual static mapping methods.
To make classes easier testable (or for some others reasons), generic mapper can be static too.
Thanks to Oliver Jacot-Descombes answer I created this solution:
//This works like static class.
public class MappingProfiles
{
//Constructor needs to be private, so that class work like static class.
private MappingProfiles() { }
private static readonly MappingProfiles _instance = new MappingProfiles();
//We need instance to invoke this class methods.
public static MappingProfiles Instance { get { return _instance; } }
public static TResult? TryMap<TSource, TResult>(TSource source)
where TResult : new()
where TSource : class, new()
{
//Trying to get mapper for result.
var resultMapper = typeof(MappingProfiles).GetMethods().FirstOrDefault(m =>
m.ReturnType == typeof(TResult) &&
m.GetParameters()[0].ParameterType == typeof(TSource));
if (resultMapper is null)
throw new Exception($"Mapper not found. From: {typeof(TSource)}, to: {typeof(TResult)}");
//Makes TSource array, because Invoke method works only with arrays.
TSource[] sources = new TSource[] { source };
//Calls manual mapping method.
object res = resultMapper.Invoke(MappingProfiles.Instance, sources);
return (TResult)res;
}
public static ExampleTo Map(ExampleFrom from)
{
return new ExampleTo
{
//...
};
}
}
To call this mapper:
var mapped = MappingProfiles.TryMap<TExampleFrom, TExampleTo>(exampleFromVariable);

Resolving generic Decorators with Simple Injector

I am trying to build out a structure where I have a base IValidator<> interface that will be generated for our system based on some metadata. We want to give future developers the flexibility to 1) Regenerate the concrete implementations of IValidator<> if need be without disturbing any hand-written code and 2) Add decorators to IValidator<> to be able to extend the functionality without disturbing the auto-generated code.
I would like to have some way to resolve the generic decorators at runtime using the RegisterDecorator method of Simple Injector so our dev team does not need to go and update the composition root every time we add a decorator.
Here are some example classes/interfaces
public interface IValidator<T> where T : class
{
void Validate(T entity);
}
public class ClientValidator : IValidator<Client>
{
public void Validate(Client entity)
{
//Auto-generated
}
}
public class UserValidator : IValidator<User>
{
public void Validate(User entity)
{
//Auto-generated
}
}
public class ClientValidatorDecorator : IValidator<Client>
{
private readonly IValidator<Client> clientValidator;
public ClientValidatorDecorator(IValidator<Client> clientValidator)
{
this.clientValidator = clientValidator;
}
public void Validate(Client entity)
{
//New rules
this.clientValidator.Validate(entity);
}
}
public class UserValidatorDecorator : IValidator<User>
{
private readonly IValidator<User> userValidator;
public UserValidatorDecorator(IValidator<User> userValidator)
{
this.userValidator = userValidator;
}
public void Validate(User entity)
{
//New rules
this.userValidator.Validate(entity);
}
}
public class ValidationContext
{
private readonly IValidator<Client> client;
private readonly IValidator<User> user;
public ValidationContext(IValidator<Client> client, IValidator<User> user)
{
this.client = client;
this.user = user;
}
}
We I am trying to do something like so:
public void RegisterServices(Container container)
{
container.Register(typeof(IValidator<>), AssemblyManifest.GetAssemblies());
container.RegisterDecorator(typeof(IValidator<>), GetType, Lifestyle.Transient, UseType);
}
private static Type GetType(DecoratorPredicateContext ctx)
{
//Return appropriate Decorator
}
private static bool UseType(DecoratorPredicateContext ctx)
{
//Predicate
}
Unfortunately, unless I resolve a concrete type RegisterDecorator throws an error, so resolving another generic seems out. I am not sure how to proceed. Is there a way to do something like this? Is there a better way to get the intended functionality without decorators? We were thinking partial classes, but that has its own set of issues.
Any help will be appreciated!
Rather than plugging in decorators you could use a Composite Validator to enable the addition of IValidator<> implementations as required. This solution would allow the code to contain multiple IValidator<>'s for the same type.
Internally your code will still be able to depend on a single IValidator<T> which would resolve to the CompositeValidator that would call zero or more validators depending on what has been registered in the container at runtime.
The composite validator:
public class CompositeValidator<T> : IValidator<T>
{
public readonly IEnumerable<IValidator<T>> validators;
public CompositeValidator(IEnumerable<IValidator<T>> validators)
{
this.validators = validators;
}
public void Validate(T item)
{
foreach(var validator in this.validators)
{
validator.Validate(item);
}
}
}
The container is configured like this:
var assemblies = new[] { typeof(IValidator<>).Assembly };
var container = new Container();
container.RegisterCollection(typeof(IValidator<>), assemblies);
container.Register(typeof(IValidator<>), typeof(CompositeValidator<>));
where the assemblies variable contains all the assemblies you want to search for validators.
When you resolve IValidator<User> using container.GetInstance<IValidator<User>>() or through constructor injection you get back CompositeValidator<User> which internally references any and all IValidator<User>'s.
The way to get decorators of a type using batch registration is by calling the GetTypesToRegister method overload that accepts a TypesToRegisterOptions object. This way you can instruct SI to return decorators as well.
container.Register(typeof(IValidator<>), assemblies);
var t1 = container.GetTypesToRegister(typeof(IValidator<>), assemblies);
var t2 = container.GetTypesToRegister(typeof(IValidator<>), assemblies,
new TypesToRegisterOptions { IncludeDecorators = true });
foreach (Type t in t2.Except(t1)) {
container.RegisterDecorator(typeof(IValidator<>), t);
}
Do note that I do not suggest using this code. #qujck's answer addresses the design issue you have with your code, and his solutions therefore brings you to a much better place.

Register generic factory for all types which implements an interface

I have generic factory
public interface IViewModelFactory<T> where T : IViewModel
{
T Create<TU>(TU par);
}
public class ViewModelFactory<T> : IViewModelFactory<T> where T : IViewModel
{
private readonly ILifetimeScope _scope;
public ViewModelFactory(ILifetimeScope scope)
{
_scope = scope;
}
public T Create<TU>(TU par)
{
return _scope.Resolve<T>(new TypedParameter(typeof(TU), par));
}
}
which I can use for resolving viewmodel factory in my window class:
public WRPersons(IViewModelFactory<MRPersons> viewModelFactory)
{
var viewModel = viewModelFactory.Create(new MRPersonsUseCaseParams { Filter = 2 });
...
}
ViewModel is implemented by following code
public class MRPersons : IViewModel
{
public MRPersons(MRPersonsUseCaseParams par)
{
_filter = par.Filter;
}
}
public class MRPersonsUseCaseParams
{
public int Filter { get; set; }
}
Registration in my composition root looks like:
var builder = new ContainerBuilder();
builder.RegisterType<ViewModelFactory<MRPersons>>().As<IViewModelFactory<MRPersons>>();
builder.RegisterType<MRPersons>();
As you can see for each new ViewModel (now its only MRPerson) I will need to create two entries into my composition root. Thus for MRCar it will be:
builder.RegisterType<ViewModelFactory<MRCar>>().As<IViewModelFactory<MRCar>>();
builder.RegisterType<MRCar>();
I would like to automatize these registration somehow. I experimented with RegisterAssemblyTypes/AsClosedTypesOf but without success. Can somebody help me?
EDIT:
Based on answer codeline
builder.RegisterType<ViewModelFactory<MRPersons>>().As<IViewModelFactory<MRPersons>>();
is replaced by
builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>));
Full automatic registration looks like:
builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass).AsSelf();
builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>));
For better testable solution it would be fine to even replace MRPersons by IMRPersons:
public class MRPersons : IViewModel, IMRPersons
{
public MRPersons(MRPersonsUseCaseParams par)
{
_filter = par.Filter;
}
}
public class MRPersonsUseCaseParams
{
public int Filter { get; set; }
}
public interface IMRPersons
{
}
Thus registration in composition root would looks like (NEED TO BE CORRECTED)
builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass).As<??????>.AsSelf();
This would allows me to pass factory into constructor in following way:
public WRPersons(IViewModelFactory<IMRPersons> viewModelFactory)
{
var viewModel = viewModelFactory.Create(new MRPersonsUseCaseParams { Filter = 2 });
...
}
EDIT2:
During chat with Cyril Durand he provided solution for ViewModelFactory without reference to ILifetimeScope. Here is a code:
public interface IViewModelFactory2<T, TU> where T : IViewModel
{
T Create(TU par);
}
public class ViewModelFactory2<T, TU> : IViewModelFactory2<T, TU> where T : IViewModel
{
private readonly Func<TU, T> _factory;
public ViewModelFactory2(Func<TU, T> factory)
{
_factory = factory;
}
public T Create(TU par)
{
return _factory(par);
}
}
My original factory is Ok too since it is presented in composition root where strong references to DI container can be used.
You want to register ViewModelFactory<> as IViewModelFactory<>, you can do it using the RegisterGeneric method.
builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>));
Then you will be able to resolve IViewModelFactory<MRCar> without any other registration.
See Registration Concepts - Open Generic Components for more information
For the second part of the question :
For better testable solution it would be fine to even replace MRPersons by IMRPersons
It is not so easy because there is no way to know which interface to use. You can use the AsImplementedInterfaces which will be equivalent to As<IMRPersons>().As<IViewModel>() but it may be a problem if you have a lot of implemented interface.
builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly())
.Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass)
.AsImplementedInterfaces();
Or you can use a convention that will register all X asIX but I'm not a big fan of this kind of registration.
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass)
.As(t => t.GetInterfaces().Where(i => i.Name.EndsWith(t.Name)));
By the way, after chatting, we figured out that you don't need a IViewModelFactory<> at all but you only need a dependency on Func<TParam, T>

Implementing the strategy pattern with generics and StructureMap

I am trying to implement the strategy pattern in my repository layer using SM and generics. For that I have an interface, IPocoRepository, which has a concrete implementation using Entity Framework. This I have managed to wire up in my Bootstrapper-file:
For(typeof(IPocoRepository<>)).Use(typeof(EntityFrameworkRepository<>));
The problem appears when I try to implement caching for this interface. In my cached class I want an instance of the base repository class, so that I can keep my design DRY. Let me outline how these three files look:
public interface IPocoRepository<T>
{
IQueryable<T> GetAll();
...
public class EntityFrameworkRepository<T> : IPocoRepository<T> where T : class
{
public IQueryable<T> GetAll()
{
...
public class CachedRepository<T> : IPocoRepository<T> where T : class
{
private IPocoRepository<T> _pocoRepository;
public CachedRepository(IPocoRepository<T> pr)
{
_pocoRepository = pr;
}
public IQueryable<T> GetAll()
{
var all = (IQueryable<T>)CacheProvider.Get(_cacheKey);
if (!CacheProvider.IsSet(_cacheKey))
{
all = _pocoRepository.GetAll();
...
Edit: I want StructureMap to return CachedRepository when IPocoRepository is requested, except when requested for in CachedRepository - then I want it to return EntityFrameworkRepository.
I know this is simple when dealing with non-generic classes:
For<ICountyRepository>().Use<CachedCountyRepository>()
.Ctor<ICountyRepository>().Is<CountyRepository>();
I tried searching the documentation for how to do this, but couldn't find anything. Any help would be appreciated!
Ok, this isn't too hard. You can use a type interceptor. Given you have the following classes:
public interface IRepository<T>{}
public class Repository<T>:IRepository<T>{}
public class RepositoryCache<T> : IRepository<T>
{
private readonly IRepository<T> _internalRepo;
public RepositoryCache(IRepository<T> internalRepo)
{
_internalRepo = internalRepo;
}
public IRepository<T> InternalRepo
{
get { return _internalRepo; }
}
}
You will then need to create a type interceptor. You can use the configurable "MatchedTypeInterceptor" provided by StructureMap for this. The interceptor will need to look for your repositories and then figure out what the generic type parameters are. Once it has the type parameters it can declare the type of cache it needs and initialize it. As part of the initialization, it will take the original repository in it's constructor. Then the interceptor will return the completed cache to whatever requested it from the ioc context. Here is the complete sequence inside a test.
This can be moved out into your registry, I just left it all together as an minimal example.
[Test]
public void doTest()
{
MatchedTypeInterceptor interceptor = new MatchedTypeInterceptor(
x => x.FindFirstInterfaceThatCloses(typeof (IRepository<>)) != null);
interceptor.InterceptWith(original =>
{
Type closedType = original.GetType()
.FindFirstInterfaceThatCloses(typeof(IRepository<>));
var genericParameters = closedType.GetGenericArguments();
var closedCacheType = typeof(RepositoryCache<>)
.MakeGenericType(genericParameters);
return Activator.CreateInstance(closedCacheType, new[] {original});
});
ObjectFactory.Initialize(x =>
{
x.For(typeof (IRepository<>)).Use(typeof (Repository<>));
x.RegisterInterceptor(interceptor);
});
var test = ObjectFactory.GetInstance<IRepository<int>>();
Assert.That(test is RepositoryCache<int>);
}

How to resolve collection with filtering parameter?

Can Castle Windsor resolve a collection filtered by a string parameter?
interface IViewFactory
{
IView[] GetAllViewsInRegion(string regionName);
}
My application defines regions as groups of IView-derived types. When I display a particular region at runtime, I want to resolve an instance of every IView type within it (a la Prism).
I've tried doing it with the Castle's Typed Factory Facility, ComponentModel Construction Contributors, and Handler Selectors, but I can't figure out how to map multiple types to a string in a way that Castle can access, nor how to extend Castle to check the string when it decides which types to try to resolve and return in the container.
Is selection by string strictly necessary? Would it be possible to instead have all IView implementations in the same "region" implement a dedicated interface that derives from IView? Then you could use WindsorContainer.ResolveAll() (passing your region-specific IView as T) to resolve the implementations for the region in question (or you could use one of the Collection Resolvers to perform constructor injection).
In general, when trying to do things like this with Windsor, I make every effort to use the type system (and Windsor's support thereof) before resorting to string-based solutions.
Update: since we confirmed that selection by string is necessary in this case, the best solution I see is to simply inspect the list of handlers in the kernel that satisfy the IView service, then filter for the implementers where the region (defined via attribute) matches what we want, then resolve those implementers. This feels a bit hackish, but if you're okay with having a direct reference to the container in your IViewFactory implementation, this appears to work fine. Below is a passing test case demonstrating the solution.
[Test]
public void Test()
{
using (var factory = new ViewFactory())
{
var regionOneViews = factory.GetAllViewsInRegion("One");
Assert.That(regionOneViews, Is.Not.Null);
Assert.That(regionOneViews, Has.Length.EqualTo(2));
Assert.That(regionOneViews, Has.Some.TypeOf<RegionOneA>());
Assert.That(regionOneViews, Has.Some.TypeOf<RegionOneB>());
var regionTwoViews = factory.GetAllViewsInRegion("Two");
Assert.That(regionTwoViews, Is.Not.Null);
Assert.That(regionTwoViews, Has.Length.EqualTo(1));
Assert.That(regionTwoViews, Has.Some.TypeOf<RegionTwoA>());
}
}
}
public interface IViewFactory
{
IView[] GetAllViewsInRegion(string regionName);
}
public class ViewFactory : IViewFactory, IDisposable
{
private readonly WindsorContainer _container;
public ViewFactory()
{
_container = new WindsorContainer();
_container.Register(
Component.For<IView>().ImplementedBy<RegionOneA>(),
Component.For<IView>().ImplementedBy<RegionOneB>(),
Component.For<IView>().ImplementedBy<RegionTwoA>()
);
}
public IView[] GetAllViewsInRegion(string regionName)
{
return _container.Kernel.GetHandlers(typeof (IView))
.Where(h => IsInRegion(h.ComponentModel.Implementation, regionName))
.Select(h => _container.Kernel.Resolve(h.ComponentModel.Name, typeof (IView)) as IView)
.ToArray();
}
private bool IsInRegion(Type implementation,
string regionName)
{
var attr =
implementation.GetCustomAttributes(typeof (RegionAttribute), false).SingleOrDefault() as RegionAttribute;
return attr != null && attr.Name == regionName;
}
public void Dispose()
{
_container.Dispose();
}
}
public interface IView {}
[Region("One")]
public class RegionOneA : IView {}
[Region("One")]
public class RegionOneB : IView {}
[Region("Two")]
public class RegionTwoA : IView {}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class RegionAttribute : Attribute
{
private readonly string _name;
public RegionAttribute(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}

Categories