lsoft / dpdtinject Goto Github PK
View Code? Open in Web Editor NEWHighly efficient compile-time general purpose DI container based on C# source generators.
Home Page: https://www.nuget.org/packages/Dpdt.Injector/
License: MIT License
Highly efficient compile-time general purpose DI container based on C# source generators.
Home Page: https://www.nuget.org/packages/Dpdt.Injector/
License: MIT License
BindAllInterfaces()
.To<A>()
.WithSingletonScope();
...
public class A : IA0, IA1, IA2, IA3
{ }
something like the following:
ScanInAssembliesWith<MyType>()
.SelectAllWith<IA<,>>() //<---
.ExcludeAllWith<IExclude>()
.FromAllInterfaces()
.ToItself()
.WithSingletonScope();
like Bind<MyClass>().ToItself().WithSingletonScope()
.
it will add an additional symmetry with conventional bindings.
add section Alternatives
and link to StrongInject
now it's possible to define max 2 binds from: Bind<a,b>() ...
it's time to increase this number to 4 :) 'Bind<a,b,c,d>()...`
we need an appropriate unit tests.
i.e. composition root assembly is free out of BL-code. post example sln in the repo. update readme.md
due to README.md
is too large now.
e.g.
Get(typeof(SomeType));
like this:
Bind<IA>().To<A>()...
public class A
{
public A(int argument = 123) { }
}
e.g.
Bind<IA>()
.WithConstScope(SomeDifferentClass.StaticReadonlyField);
ICluster
IResolution
CarcassCluster
CustomScopeObject
DpdtException
DpdtExceptionTypeEnum
IResolutionFast
IResolutionRequest
IResolutionTarget
DefaultCluster
IToOrConstantBinding
(here is few of them)From(...)
.Select(...)
.BindTo(...)
like ninject.conventions, but working at compile time with Roslyn metadata (instead on reflection at runtime).
at this time we compile each factory independently. we need to refactor this behaviour.
it is possible to collect all (extended) BindingContainerTypes
, then generate all factories, then compile that factories, and after that build all IBindingContainer
's
we need to check that dispose object will be disposed even if exception has been fired during a resolution process.
like so:
public class BaseClass : IDisposable { public bool Disposed; public void Dispose() { Disposed = true; } }
public class DerivedClass { public DerivedClass(BaseClass bc) { throw new InvalidOperationException(); } }
Bind<BaseClass>()
.To<BaseClass>()
.WithSingletonScope()
;
Bind<DerivedClass>()
.To<DerivedClass>()
.WithSingletonScope()
;
try
{
cluster.GetFast(default(DerivedClass));
Assert.Fail("this line should never be executed");
}
catch(InvalidOperationException)
{
//it's OK
}
var baseClass = cluster.GetFast(default(BaseClass));
Assert.IsFalse(baseClass.Disposed);
cluster.Dispose();
Assert.IsTrue(baseClass.Disposed);
public interface IA
{
string ConcreteType
{
get;
}
[Telemetry]
void DoSomething();
}
it generates
public string get_ConcreteType()
{
return _payload.get_ConcreteType();
}
so the result is
(198,35): error CS0535: "AProxy" не реализует член интерфейса "IA.ConcreteType".
(44,24): error CS0470: Метод "AProxy.get_ConcreteType()" не может реализовать метод доступа интерфейса "IA.ConcreteType.get" для типа "AProxy". Используйте явную реализацию интерфейса.
we need unit test for that
also we need to use an attribute InternalsVisibleTo
to make these classes visibile to Dpdt.Generator(.Core) and extension.
it is unclear now hot it will affect unit tests.
subj
we need to produce identical code if the source code is same as before. It is a VS requirement, that I does not understand to be honest.
We can use Span-information to produce unique suffixes instead of Guid-based approach we have now.
and raise a compilation error if found
we want to have a set of radiobuttons: AllAndOrderConstructorSetting
SubsetAndOrderConstructorSetting
SubsetNoOrderConstructorSetting
(probably, at the choose constructor page)
because of strange error:
Error CS0030 Cannot convert type 'MainCluster' to 'DpdtInject.Injector.IResolution<T>'
we need check sealed
bit and make loud and clear error message.
Consider the following code:
namespace MyCompany.MyProduct.System
{
class Program
{
static void Main() => /*global::*/System.Console.WriteLine("real");
}
class Console
{
string Suggestion => "Consider renaming this class";
public static void WriteLine(string s) => global::System.Console.WriteLine("fake");
}
}
without global::
its output is fake
.
subj
We need to have an additional method like CheckConfiguration
that perform an additonal checks for cross cluster issues.
long this[int i]
{
get;
set;
}
the framework allows SG to append not only CS files, but some additional files.
we may put some XML or txt file with info about produced bindings, their details, and their source code position.
if I include dpdt as a nuget, it requires an absolute path, relative path will not working.
currently we have no access to the fields of cluster, but it's a very good feature that I want to have in.
public class MyCluster : DefaultCluster
{
private readonly A _a;
public MyCluster(A a)
{
_a = a;
}
public void Load()
{
Bind<IA>().ToMethod( () => _a ); //???
Bind<IA>().WithConstScope( () => _a ); //??? looks preferable
}
}
if the user forgot to dispose custom scope object, we need to invoke dispose in finalization method. so custom scope object should implement full-blown dispose pattern with finalization machnery on.
after implementing, you need to update readme.md (section custom scope).
test + fix
Bind<IA1>().To<IA2>()...
is invalid.
exception should be thrown at runtime in such cases.
'Isolated' means that factored objects did not taken from the container, but constructed inside its factory.
At first we need a factory source code generator based on roslyn symbols, not a reflection.
TODO: unit tests to test the factory.
ways:
steps:
disallow to the any cluster type to be a source\target for binding clauses.
e.g. do not allow following:
public partial class Cluster0 : DefaultCluster {...}
public partial class Cluster1 : DefaultCluster
{
[DpdtBindingMethod]
public void BindMethod0()
{
Bind<Cluster0>().To<Cluster0>()...;
}
}
how can we create a mode, when produced assembly will not have any dependency of Dpdt?
It is clear even now that
DefaultCluster
somehow, or copy it to the processed project. Also we need to do exact the same with IResolutionTarget
etc (conditional bindings).It is good to hide an unnecessary details from your clients. So it's good thing to change an open modifiers to a more restricted modifiers, e.g. public
-> internal
or private
even. Also perform a work with InternalsVisibleTo
here (if it will require).
describe how to exclude concrete type from conventional-binding statement, and show how to bind it to proxy.
i.e. we have Class0
, Class1
, Class2
, ... , ClassN
binded from single conventional statement. but we want to bind Class2
to proxy, and leave the others classes untouched. Let's show how it possible.
and may be something more.
public static class ResolutionTargetHelper
{
public static bool WhenInjectedExactlyInto<T>(this IResolutionTarget rt) => return ....;
}
what do we need to change to add natural support for blazor and asp.net environments?
intendation can be taken something like the following:
var textManager = (IVsTextManager)packageServiceProvider.GetRequiredService(typeof(SVsTextManager));
textManager.GetActiveView(1, null, out IVsTextView currentView);
var model = (IComponentModel)packageServiceProvider.GetService(typeof(SComponentModel));
var editorAdapters = model.GetService<IVsEditorAdaptersFactoryService>();
var textView = editorAdapters.GetWpfTextView(currentView);
var indentSz = textView.Options.GetOptionValue(DefaultOptions.IndentSizeOptionId);
Probably we need to have a window, where a binding list can be seen in human readable format. May be with some searching functionality. May be with go-to functionality.
(this information can be taken from binding xml produced by Dpdt source generator)
No details available now, only the idea.
namespace <global namespace>
from
//the following statement will bind A0 and A2; A1 will be excluded due to IExclude<>
ScanInAssembliesWith<A0>()
.SelectAllWithOpenGeneric<IA<object, object>>() //generic arguments 'object' means NOTHING! it will be removed by Dpdt, so IA<object,, object> will be transformed into IA<,> (open generic)
.ExcludeAllWithOpenGeneric<IExclude<object, object>>() //again, 'object' means nothing, as above
.FromAllInterfaces()
.ToItself()
.WithSingletonScope()
;
to something like the following:
//the following statement will bind A0 and A2; A1 will be excluded due to IExclude<>
ScanInAssembliesWith<A0>()
.SelectAllWithOpenGeneric<IA<DpdtAny, object, ConcreteClass>>()
//generic argument 'DpdtAny' means NOTHING! it will be removed by Dpdt, so IA<DpdtAny, object, ConcreteClass> will be transformed into IA<, object, ConcreteClass> (open generic)
.ExcludeAllWithOpenGeneric<IExclude<DpdtAny>>() //again, 'DpdtAny' means nothing, as above
.FromAllInterfaces()
.ToItself()
.WithSingletonScope()
;
or even more powerful
//the following statement will bind A0 and A2; A1 will be excluded due to IExclude<>
ScanInAssembliesWith<A0>()
.SelectAllWithOpenGeneric<IA<DpdtAny, ConcreteClass, DpdtChild<ConcreteClass>>>()
//generic argument 'DpdtAny' means NOTHING! it will be removed by Dpdt; DpdtChild<> means any children of this type; so IA<DpdtAny, ConcreteClass, DpdtChild<ConcreteClass>> will be transformed into IA<, ConcreteClass, any child class of ConcreteClass> (open generic)
.ExcludeAllWithOpenGeneric<IExclude<DpdtAny>>() //again, 'DpdtAny' means nothing, as above
.FromAllInterfaces()
.ToItself()
.WithSingletonScope()
;
the last has more complex syntax, it's a disadvantage. If target type for SelectAllWithOpenGeneric
does not have at least one DpdtAny
or DpdtChild<>
, it's a incorrect configuration and should results into appropriate compilation error.
So, we need to
DpdtAny
, and may be DpdtChild<>
IT'S A BREAKING CHANGE!
Look at lsoft/DpDtInject.Old#16. When Microsoft allows that source generators to be targeted not only netstandard2.0
, we need to remove applied workaround.
-- CAUTON! EVERY SETTING WORKS ONLY IN COMPILE-TIME (during cluster code producing), NOT IN RUNTIME! --
how to set this in binding?
Relate with checking for child binding resolutions; useful for an additional safety. Applied for each of child resolutions.
Each dependency must exists in local cluster. If not - ongoing compilation will break. Note: binding conditions is out of scope, only existing matters. You can define a local binding with When(rt => false)
, and this check will mute. So, this setting is not something that can protect you at 100%. This is a default behaiour.
Any dependency may be in home cluster or parent cluster. If local dependecy found at runtime it is used, otherwise request to the parent cluster is performed. (this is default behaviour for old version of Dpdt)
NO local dependency allowed, any dependency MUST be in the parent cluster. If local dependency found, ongoing compilation will break. Note: binding conditions is out of scope, only existing matters. You can define a local binding with When(rt => false)
, and this check will fire. So, this setting is not something that can protect you at 100%.
Relate with producing wrapped-resolutions, like Func<>
; it is useful for minimizing cluster size.
No bindings for wrappers will be produced. It is a default value;
Every type of wrappers will be produced for this binding.
Relate with a circular checking; useful for removing unused noise from build log (for example in case of decorator).
Do circular checking. It is a default value;
Do not circular checking. Use this for decorators bindings.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.