0

I'm using the LINQ Zip() method do create a Dictionary<TAbstraction,TImplementation> in order to register all my types in a DI Container.

The TAbstraction are the exposed Types with names that ends with Repository from an Assembly , and the TImplementation are the implementations (with name that ends with Repository) of the abstraction located in another assembly.

So far, I've ordered the two IEnumerable by Type.Name, and the registration can be performed but is very fragile.

I've kept the types in my assembly named after a convention (the abstraction has to be called [objectname]Repository, and the implementation Sql[objectname]Repository).

The result lists are ordered alphabetically, so if I add an interface called I[objectname]Repository (or more likely if a developer after me will do that) the list order will be messed up.

The dictionary is created like this:

var dictionary = repositories.Zip(repositoriesImp, (r, rImp) => new { r, rImp })
                                          .ToDictionary(x => x.r, x => x.rImp);

I'd like to introduce a where clause in or after the Zip() method in order to avoid unexpected errors, something like this

var dictionary = (from r in repositories
                 join rImp in repositoriesImp
                 on //?
                 where rImp.Name.Contains(r.Name)
                 select new{
                     Key = r,
                     Value = rImp
                 }).ToDictionary(x=>x.Key,x=>x.Value);

From the MSDN I've seen that the delegate Func<TFirst, TSecond, TResult> you can perform some operations (they use a ternary operator), so I'm wondering if you can check the Type.Name from there.

  • Your question is quite unclear at the moment, particularly given that you don't appear to want to order the dictionary. It would help if you'd provide a short but *complete* example instead of snippets. – Jon Skeet Jul 28 '14 at 15:11
  • "to avoid unexpected errors" - what are those unexpected errors? What is the goal? What is the problem? – Eugene Podskal Jul 28 '14 at 15:12
  • Say I have an `IStuffRepository`,`IDataRepository` that have implementations called `SqlStuffRepository` and `SqlDataRepository`. If and someone will create an abstract class `FooRepository` with implementation `SqlFooRepository` the lists will have different order and the registration will fail. –  Jul 28 '14 at 15:24
  • Your (edited) comment still does not make much sense. You did not explain how FooRepository/SqlFooRepository relates to the other two interfaces you mentioned, and how this would be important for the order of whatever registration you do... –  Jul 28 '14 at 15:29
  • If i understand the code in your question correctly, you are using a dictionary, but you want to rely on some order of the elements stored in the dictionary based on the key of that dictionary, correct? If this is correct, why wouldn't you use a SortedDictionary? –  Jul 28 '14 at 15:44
  • I want the `Key.Name` to be contained in the `Value.Name` to be sure that every abstraction is paired with its own implementation. –  Jul 28 '14 at 15:46
  • I am not sure i understand your last comment correctly. A *TAbstraction* key could be for example `IStuffRepository`. According to your last comment, the implementing type of that interface must be named something like `SomethingIStuffRepositorySomething`. But according to your question, `Value.Name` should only contain a **part** of `Key.Name` (like "Stuff"). I am confused... –  Jul 28 '14 at 15:49
  • If the latter is the case (i.e., both *Key.Name* and *Value.Name* should contain the same relevant part of the type name), then don't use *string.Contains()*, obviously. Rather substitute the call of string.Contains() with your own predicate method (like `bool AreInterfaceAndConcreteTypeMatching(Type interface, Type impl`) in which you wrangle the type names and test whether the implementation belongs to the interface passed to that method. (You can implement this as an anonymous method as part of a lambda expression, or declare this method explicitly in one of your classes) –  Jul 28 '14 at 16:00
  • However, instead of wrangling with the type name strings it would be perhaps be better and certainly more robust to directly test if a concrete class implements a given interface (using reflection). Look here: [How to determine if a type implements an interface with C# reflection](http://stackoverflow.com/questions/4963160/how-to-determine-if-a-type-implements-an-interface-with-c-sharp-reflection) –  Jul 28 '14 at 16:03

2 Answers2

0
var dictionary = repositories.Join(repositoriesImp, 
                                   x => x.Name, 
                                   y => y.Name, 
                                   (x, y) => new { Key = x, Value = y))
                             .ToDictionary(a => a.Key , a => a.Value );
Konrad Kokosa
  • 16,563
  • 2
  • 36
  • 58
0

It was my approach that was wrong. I've used reflection to create my dictionary in the right way:

var repositoriesImp = typeof(SqlDataRepository).Assembly.GetExportedTypes()
                                  .Where(t => t.Name.EndsWith("Repository"))
                                  .ToList();
var dictionary = new Dictionary<Type, Type>();
foreach (var repositoryImp in repositoriesImp)
{
    var repository = typeof(DataRepository).Assembly.GetExportedTypes()
                                     .Where(t => repositoryImp.IsSubclassOf(t))
                                     .Single();
    dictionary.Add(repository, repositoryImp);
}

Thanks everyone for pointing me in the right direction.