Giter Site home page Giter Site logo

lsoft / dpdtinject Goto Github PK

View Code? Open in Web Editor NEW
32.0 32.0 3.0 4.22 MB

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

C# 99.96% Batchfile 0.04%
csharp csharp-sourcegenerator dependency-injection di-container di-framework inversion-of-control ioc performance source-generators sourcegenerator visual-studio-extension vsix-extensions

dpdtinject's People

Contributors

lsoft avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

dpdtinject's Issues

conventional bindings: open generics

something like the following:

ScanInAssembliesWith<MyType>()
    .SelectAllWith<IA<,>>()   //<---
    .ExcludeAllWith<IExclude>()
    .FromAllInterfaces()
    .ToItself()
    .WithSingletonScope();

more bind froms

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.

add `///` comments on main components

  • ICluster
  • IResolution
  • CarcassCluster
  • CustomScopeObject
  • DpdtException
  • DpdtExceptionTypeEnum
  • IResolutionFast
  • IResolutionRequest
  • IResolutionTarget
  • DefaultCluster
  • all of binding interfaces like IToOrConstantBinding (here is few of them)
  • any more?

design conventional bindings

From(...)
.Select(...)
.BindTo(...)

like ninject.conventions, but working at compile time with Roslyn metadata (instead on reflection at runtime).

performance optimization: compile all factories at once

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

dispose: additonal test

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);

Proxy do not support properties

    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

cluster type cannot be sealed

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.

Binding that gives access to readonly fields of Cluster

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
    }
}

Custom scope object dispose guard

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).

Implement `ToIsolatedFactory`

'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.

cluster type as binding source\target

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>()...;
    }
}

standalone mode

how can we create a mode, when produced assembly will not have any dependency of Dpdt?

It is clear even now that

  1. We need new nuget package that contains only Source Generator and no regular assembly.
  2. We need to remove DefaultCluster somehow, or copy it to the processed project. Also we need to do exact the same with IResolutionTarget etc (conditional bindings).
  3. another binding syntax (without DefaultCluster)? Do improve a separation between parsing and producing bindings stages?

replace access modifiers to appropriate ones

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).

update readme: special cases in conventional clause

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.

implement WhereInjectedExactlyInto<T>

and may be something more.

public static class ResolutionTargetHelper
{
     public static bool WhenInjectedExactlyInto<T>(this IResolutionTarget rt) => return ....;
}

check for using a correct intendation during addition of a new binding clause

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);

Dpdt VSE: human readable information about project's bindings?

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.

improve open generics?

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

  1. Add a DpdtAny, and may be DpdtChild<>
  2. Modify the conventional binding algorithm to support these classes (tricky part!).
  3. Modify readme.md

IT'S A BREAKING CHANGE!

binding settings

-- CAUTON! EVERY SETTING WORKS ONLY IN COMPILE-TIME (during cluster code producing), NOT IN RUNTIME! --

  • Cross cluster resolutions
  • Wrapper producing
  • Circular checking
  • More?

how to set this in binding?

Cross cluster resolutions

Relate with checking for child binding resolutions; useful for an additional safety. Applied for each of child resolutions.

  • OnlyLocalCluster
  • AllowedCrossCluster
  • MustBeCrossCluster

OnlyLocalCluster

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.

AllowedCrossCluster

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)

MustBeCrossCluster

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%.

Wrapper producing

Relate with producing wrapped-resolutions, like Func<>; it is useful for minimizing cluster size.

  • NoWrappers
  • ProduceWrappers

NoWrappers

No bindings for wrappers will be produced. It is a default value;

ProduceWrappers

Every type of wrappers will be produced for this binding.

Circular checking

Relate with a circular checking; useful for removing unused noise from build log (for example in case of decorator).

  • PerformCircularCheck
  • SuppressCircularCheck

PerformCircularCheck

Do circular checking. It is a default value;

SuppressCircularCheck

Do not circular checking. Use this for decorators bindings.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.