c# - Getting interface implementations in referenced assemblies with Roslyn -
i'd bypass classical assembly scanning techniques in framework developing.
so, i've defined following contract:
public interface imodule { }
this exists in contracts.dll
.
now, if want discover implementations of interface, similar following:
public ienumerable<imodule> discovermodules() { var contracttype = typeof(imodule); var assemblies = appdomain.current.getassemblies() // bad var types = assemblies .selectmany(a => a.getexportedtypes) .where(t => contracttype.isassignablefrom(t)) .tolist(); return types.select(t => activator.createinstance(t)); }
not great example, do.
now, these sorts of assembly scanning techniques can quite under-performaning, , done @ runtime, typically impacting startup performance.
in new dnx environment, can use icompilemodule
instances metaprogramming tools, bundle implementation of icompilemodule
compiler\preprocess
folder in project , funky.
what target be, use icompilemodule
implementation, work @ runtime, @ compile time instead.
- in references (both compilations , assemblies), , current compilation, discover instaniatable instances of
imodule
- create class, lets call
modulelist
implementation yields instances of each module.
public static class modulelist { public static ienumerable<imodule>() getmodules() { yield return new module1(); yield return new module2(); } }
with class added compilation unit, invoke , static list of modules @ runtime, instead of having search through attached assemblies. we're offloading work on compiler instead of runtime.
given can access references compilation via references
property, can't see how can useful information, such maybe access byte code, perhaps load assembly reflection, or that.
thoughts?
thoughts?
yes.
typically in module environment want dynamically load module based on context, or - if applicable - third party. in contrast, using roslyn compiler framework, information compile-time, thereby restricting modules static references.
just yesterday posted code dynamic loading of factories wth. attributes, updates loading dll's etc here: naming convention gof factory? . understand, it's quite similar you're trying achieve. upside of approach can dynamically load new dll's @ runtime. if try it, you'll find it's quite fast.
you can further restrict assemblies process. example, if don't process mscorlib
, system.*
(or perhaps gac assemblies) it'll work lot faster of course. still, said, shouldn't problem; scanning types , attributes quite fast process.
ok, bit more information , context.
now, might possible you're looking fun puzzle. can understand that, toying around technology after lot of fun. answer below (by matthew himself) give information need.
if want balance pro's , cons of compile-time code generation versus runtime solution, here's more information experience.
some years back, decided idea have own c# parser/generator framework ast transformations. it's quite similar can roslyn; converts entire project ast tree, can normalize, generate code for, checks on aspect-oriented programming stuff , add new language constructs. original goal here add support aspect oriented programming c#, had practical applications. i'll spare details, context it's sufficient module / factory based on code generation 1 of things i've experimented well.
performance, flexibility , amount of code (in non-library solution) key aspects me weighting decision between runtime , compile time decision. let's break them down:
- performance. important because cannot assume library code not on critical path. runtime cost few milliseconds per appdomain instance. (see below remarks on how/why).
- flexibility. they're both equally flexible in terms of attribute / scanning. however, @ runtime have more possibilities in terms of changing rules (e.g. dynamically plugging modules etc). use this, particularly based on configuration, don't have develop in same solution (because that's inefficient).
- amount of code. rule of thumb, less code better code. if right, both result in single attribute need on class. in other words, both solutions give same result here.
a note on performance in order though. use reflection more factory patterns in code. have extensive library here of 'tools' include design patterns (and ton of other things). few examples: automatically generate code @ runtime things factories, chain-of-responsibility, decorators, mocking, caching / proxies (and more). of these required me scan assemblies.
as simple rule of thumb, use attribute denote has changed. can use advantage: storing every type attribute (of correct assembly/namespace) in singleton / dictionary somewhere, can make application lot faster (because need scan once). it's not useful scan assemblies microsoft. did lot of tests on large projects, , found in worst case found, scanning added approximately 10 ms startup time of application. note once per instantiation of appdomain, means won't notice it, ever.
activation of types 'real' performance penalty get. penalty can optimized away emitting il code; it's not difficult. end result won't make difference here.
to wrap up, here conclusions:
- performance: insignificant difference.
- flexibility: runtime wins.
- amount of code: insignificant difference.
from experience, although lot of frameworks hope support plug , play architectures benefit drop in assemblies, reality is, there isn't whole load of use-cases applicable.
if it's not applicable, might want consider not using factory pattern in first place. also, if applicable, i've shown there isn't real downside it, is: iff implement properly. unfortunately have acknowledge here i've seen lot of bad implementations.
as fact it's not applicable, think that's partly true. it's quite common drop-in data providers (it logically follows 3-tier architecture). use factories wire things communication/wcf api's, caching providers , decorators (that logically follows n-tier architecture). speaking it's used kind of provider can think of.
if argument gives performance penalty, want remove entire type scanning process. personally, use ton of different things, notably caching, statistics, logging , configuration. also, believe performance downside negliable.
just 2 cents; hth.
Comments
Post a Comment