Code Monkey home page Code Monkey logo

vcontainer's People

Contributors

adarapata avatar adoringonion avatar airtonmotoki avatar alontalmi avatar alvinsay avatar c3-hoge-fuga-piyo avatar ceceomer avatar cooloon avatar denispimenov avatar dependabot[bot] avatar github-actions[bot] avatar hadashia avatar ishix-g avatar jessetg avatar joe2643 avatar konh avatar longbombus avatar mackysoft avatar perasite avatar piti6 avatar pnarimani avatar pspgit avatar revolt3r avatar sakano avatar shiena avatar slimshader avatar stenyin avatar veyronsakai avatar yegorstepanov avatar yuukiaria 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  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  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  avatar  avatar  avatar  avatar

Watchers

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

vcontainer's Issues

How can I inject dependencies into nested objects?

I'm trying to use VContainer to inject dependencies into nested objects that are not derived from MonoBehaviour. Here's what I mean.

Suppose I represent my game logic in systems like so:

public sealed class PhysicsSystem : IExecuteSystem
{
    private readonly IPhysicsService _physics;
    private readonly ITimeService _time;
    private readonly IPhysicsConfig _physicsConfig;

    public PhysicsSystem(IPhysicsService physics, ITimeService time, IPhysicsConfig physicsConfig)
    {
        // Initialization
    }

    public void Execute()
    {
        // Logic goes here
    }
}

I have dozens of these systems, nearly all of which depend on some common services or configuration objects. To keep my code manageable, I group them in System-like objects called Features. This results in a logical tree-like structure. Here's an example:

public sealed class GameplayFeature : Feature
{
    public GameplayFeature()
    {
        Add(new PhysicsSystem(/* ... */));
        Add(new AiFeature(/* ... */));
    }
}

Note that the order in which these systems are declared and added is important.

The naive thing would be to register every System and Feature, with the top-most Feature -- let's call it FullGameFeature -- having an enormous constructor that passes in every possible dependency in my game. This is not feasible.

So what would you suggest? My requirements are:

  • The ability to initialize individual systems with constructor injection
  • The ability to define each of a Feature's Systems within its constructor
  • The ability to keep the overall tree structure of my Systems and Features

One thing I won't do is to inject the IObjectResolver into all Features and Systems, as my current home-grown dependency injection framework already does something similar to that. If VContainer requires me to do this, then there will be no advantage in adopting it.

Refine documentation

The long README has usability problems, so I would like to consider creating a website.

  • Introduce docusaurus, Create website
  • Fix some styles and docs
  • Deployment
  • Fix github README and meta
  • Search bar
  • Translate japanese

Please support Container.Instantiate<class>()

sorry my english,i use google translate

This sometimes happens in projects. I need to create a class and inject property, and assign the class to a local variable.
That's all I can do now.

    public class A
    {
        [Inject] private string B;
        public A()
        {
            
        }  
    }

    public class B
    {
        public B()
        {
            var C = new A();
            xxx.Inject(C);
            C........
        }
    }

I would like to have a method similar to the Instantiate method in Zenject.
That way I can put variables in the constructor. And it would be much smoother to write

ヒエラルキー上の複数のオブジェクトに対してRegisterComponentInHierarchy()が動かない

このようなコンポーネントを作り、ICameraRigをinjectしています

// 実行時にparentを変更するだけのスクリプト
public class ParentToTrackingPoint : MonoBehaviour
{
    ICameraRig cameraRig;
    [Inject]
    public void Construct(ICameraRig cameraRig)
    {
        this.cameraRig = cameraRig;
        Debug.Log(cameraRig);
    }
    [SerializeField]
    private TrackingPoint trackingPoint;
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log(cameraRig);
        var t = cameraRig.GetTransform(trackingPoint);
        transform.SetParent(t, false);
        
    }

}

configure

        builder.RegisterEntryPoint<OculusCameraRig>(Lifetime.Singleton); //ICameraRigの実装
        builder.RegisterComponentInHierarchy<ParentToTrackingPoint>();

このとき、ヒエラルキー上でこのコンポーネントを持つオブジェクトが複数ある場合、最初の一つのみにinjectされているようです。
ヒエラルキー上で2つのオブジェクトの順番を入れ替えると、最初の方のみが正しく動いています。

これはバグでしょうか?それとも私のDIに関する勘違いでしょうか?(当方Unityのプログラミングに慣れていないため勘違いであったら申し訳ないです)

Cannot register System.Type in IContainerBuilder

I want to register all the types I need that derive from a certain interface, and there's no way to do this:

var baseType = typeof(IUseCase);
var assembly = baseType.Assembly;
var useCaseTypes = assembly.GetTypes()
    .Where(t => baseType.IsAssignableFrom(t));
foreach (var useCaseType in useCaseTypes)
{
    builder.Register(useCaseType, Lifetime.Transient);
}

Resolve dependencies of prefab on instantiation

Hello! Just started using VContainer and liking it, but I have a problem and can't figure out the solution. I want to create a factory that creates instances of some base class but resolves the dependencies of its descendants. Here is the example:

    public class ScreenService
    {

        private Dictionary<string, ScreenBase> _screenPrefabs;

        // this is the subject of question
        private SomeMagicFactory _someMagicFactory;
        
        public void Show(string screenName)
        {
            _someMagicFactory.Instatiate(_screenPrefabs[screenName]);
        }
        
        // some other code
        
    }
    public abstract class ScreenBase: MonoBehaviour
    {
        // some base class code
    }
    
    public class LoginScreen : ScreenBase
    {

        private ILoginService _loginService;

        [Inject]
        public void Construct(ILoginService loginService)
        {
            _loginService = loginService;
        }
        
        // some login screen specific code that uses ILoginService

    }

    public class SomeOtherScreen : ScreenBase
    {
        private ISomeService _someService;

        [Inject]
        public void Construct(ISomeService someService)
        {
            _someService = someService;
        }
        
        // some screen code
    }

With the current factory approach in VContainer I can't use one factory to instantiate/resolve dependencies at runtime in classes inherited from ScreenBase, because that would require me to create different factory for each class that inherits ScreenBase.

In Zenject, e.g. creating that sort of factory is pretty easy:

        public class Factory : PlaceholderFactory<UnityEngine.Object, ScreenBase>
        {
        }

And this factory will resolve all dependencies of classes that inherit from ScreenBase automatically.

It also will resolve dependencies not only on direct descendant of ScreenBase, but dependencies of all MonoBehaviour classes with [Inject] attribute on target GameObject. But thats out of question, nice feature, but not required at all.

Is it possible to achieve desired behaviour with VContainer?

TestRunner raises StackOverflowException when scripts are in Assembly-CSharp

Project

Assets/
└ Scenes/
    └ SampleScene.unity
└ Foo.cs
public class Foo { }

Versions

  • Unity Editor 2020.3.0f1
  • VContainer v1.6.0
  • Test Runner 1.1.24

Description

See below for the English version.

  1. MonoBehaviourを継承していないクラスをasmdefを切らずに作成する(Assembly-CSharpに含める)
  2. VContainerをインストールする
  3. UnityEditorの Window>General>Test RunnerからTest Runnerタブを開く

この一連の流れによって、StackOverflowExceptionが起きてから無限にNullReferenceExceptionが表示されるようになります。
コードをAssembly-CSharp以外のasmdefに収めることで解消します。
エラーが出ている間はTest Runnerがテストケースを読んでくれない状態になるため、Test Runnerが使えないという状態です。

バグなのかどうか、またバグだったとしてもVContainerのものなのか、TestRunnerのものなのかが掴めておらず申し訳ないのですが、確認していただければ幸いです。

  1. create a class that does not inherit MonoBehaviour without compiling them into user's asmdef (include it into predefined Assembly-CSharp)
  2. install VContainer
  3. open the Test Runner tab from Window > General > Test Runner in Unity Editor

This raises a StackOverflowException and an infinite NullReferenceExceptions.
If you compile the codes into another asmdef other than Assembly-CSharp, it works.
While the error is happening, Test Runner won't read your test cases, so you can't use Test Runner.

I don't know if this is a bug or expected, and even if it is, I don't know if it's a VContainer's or a TestRunner’s, so I would appreciate it if you could check.

Logs

StackOverflowException: The requested operation caused a stack overflow.
System.Globalization.CultureInfo.CreateCulture (System.String name, System.Boolean reference) (at :0)
System.Reflection.AssemblyName.FillName (Mono.MonoAssemblyName* native, System.String codeBase, System.Boolean addVersion, System.Boolean addPublickey, System.Boolean defaultToken, System.Boolean assemblyRef) (at :0)
System.Reflection.Assembly.GetReferencedAssemblies (System.Reflection.Assembly module) (at :0)
System.Reflection.MonoAssembly.GetReferencedAssemblies () (at :0)
UnityEditor.TestTools.TestRunner.EditorAssemblyWrapper.GetReferencedAssemblies () (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/TestRunner/Utils/EditorAssemblyWrapper.cs:13)
UnityEditor.TestTools.TestRunner.EditorLoadedTestAssemblyProvider.FilterAssemblyForTestReference (UnityEngine.TestTools.Utils.IAssemblyWrapper assemblyToFilter, UnityEngine.TestTools.Utils.IAssemblyWrapper[] loadedAssemblies, System.Collections.Generic.IDictionary2[TKey,TValue] filterResults) (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/TestRunner/Utils/EditorLoadedTestAssemblyProvider.cs:86) UnityEditor.TestTools.TestRunner.EditorLoadedTestAssemblyProvider.FilterAssemblyForTestReference (UnityEngine.TestTools.Utils.IAssemblyWrapper assemblyToFilter, UnityEngine.TestTools.Utils.IAssemblyWrapper[] loadedAssemblies, System.Collections.Generic.IDictionary2[TKey,TValue] filterResults) (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/TestRunner/Utils/EditorLoadedTestAssemblyProvider.cs:101)
UnityEditor.TestTools.TestRunner.EditorLoadedTestAssemblyProvider.FilterAssemblyForTestReference (UnityEngine.TestTools.Utils.IAssemblyWrapper assemblyToFilter, UnityEngine.TestTools.Utils.IAssemblyWrapper[] loadedAssemblies, System.Collections.Generic.IDictionary2[TKey,TValue] filterResults) (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/TestRunner/Utils/EditorLoadedTestAssemblyProvider.cs:101) UnityEditor.TestTools.TestRunner.EditorLoadedTestAssemblyProvider.FilterAssemblyForTestReference (UnityEngine.TestTools.Utils.IAssemblyWrapper assemblyToFilter, UnityEngine.TestTools.Utils.IAssemblyWrapper[] loadedAssemblies, System.Collections.Generic.IDictionary2[TKey,TValue] filterResults) (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/TestRunner/Utils/EditorLoadedTestAssemblyProvider.cs:101) < message truncated >

NullReferenceException: Object reference not set to an instance of an object
UnityEditor.TestTools.TestRunner.GUI.TestTreeViewBuilder.ParseTestTree (System.Int32 depth, UnityEditor.IMGUI.Controls.TreeViewItem rootItem, UnityEditor.TestTools.TestRunner.Api.ITestAdaptor testElement) (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/GUI/TestListBuilder/TestTreeViewBuilder.cs:54)
UnityEditor.TestTools.TestRunner.GUI.TestTreeViewBuilder.BuildTreeView (UnityEditor.TestTools.TestRunner.GUI.TestFilterSettings settings, System.Boolean sceneBased, System.String sceneName) (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/GUI/TestListBuilder/TestTreeViewBuilder.cs:35)
UnityEditor.TestTools.TestRunner.GUI.TestListTreeViewDataSource.FetchData () (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/GUI/TestListTreeView/TestListTreeViewDataSource.cs:37)
UnityEditor.IMGUI.Controls.TreeViewDataSource.ReloadData () (at /Users/bokken/buildslave/unity/build/Editor/Mono/GUI/TreeView/TreeViewDataSource.cs:54)
UnityEditor.IMGUI.Controls.TreeViewController.ReloadData () (at /Users/bokken/buildslave/unity/build/Editor/Mono/GUI/TreeView/TreeViewController.cs:298)
UnityEditor.TestTools.TestRunner.GUI.TestListGUI.Reload () (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/GUI/Views/TestListGUIBase.cs:202)
UnityEditor.TestTools.TestRunner.TestRunnerWindow+<>c__DisplayClass27_0.b__0 (UnityEditor.TestTools.TestRunner.Api.ITestAdaptor rootTest) (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/TestRunnerWindow.cs:162)
UnityEditor.TestTools.TestRunner.Api.TestRunnerApi+<>c__DisplayClass8_0.b__0 (UnityEditor.TestTools.TestRunner.Api.ITestAdaptor testRoot) (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/Api/TestRunnerApi.cs:143)
UnityEditor.TestTools.TestRunner.TestListJob.EditorUpdate () (at Library/PackageCache/[email protected]/UnityEditor.TestRunner/TestRunner/Utils/TestListJob.cs:31)
UnityEditor.EditorApplication.Internal_CallUpdateFunctions () (at /Users/bokken/buildslave/unity/build/Editor/Mono/EditorApplication.cs:327)

RegisterInstanceで登録したインスタンスの生存期間を設定したい

ver1.6.0現在、RegsiterInstanceで登録したインスタンスは全てLifetime.Scopedで管理されているようです。
それによってIDisposableを実装したインスタンスがLifetimeScopeごとにDisposeされてしまっています。

LifetimeScopeに親子関係を持たせる場合、子のLifetimeScopeが破棄されると親のLifetimeScopeでも登録したインスタンスがDisposeされた状態になるので困ってしまいます。

RegisterInstanceのタイミングでLifetimeも指定できるAPIがあると嬉しいです。

VContainer.EnableCodeGenを参照したアセンブリがあるとビルドが失敗する(Unity 2021以降のみ?)

お世話になっております。

Unity 2021.2.0a13 (Windows)にて、 VContainer 並びに VContainer.EnableCodeGenAssembly Definition References に追加した asmdef があると次のエラーでビルドが失敗してしまうようになっておりました。

(0,0): error VContainer failed pre code gen for <Module> : Could not load file or assembly '該当のアセンブリ名, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. General Exception (0x80131500)

最小の手順としては次になります。

  1. 適当なディレクトリに asmdef を作る
  2. (1) の Assembly Definition ReferencesVContainerVContainer.EnableCodeGen を追加する(コード生成の対象にする)
  3. (1) のディレクトリに適当なスクリプトを追加する
  4. ビルド実行
  5. 失敗する

またこちらですが、手元では 2021.1.3f12021.2.0a10 ~ 13(10より前については確認していません……) でも同様のエラーが発生しておりました( 2020.3.4f12019.4.23f1 では問題なくビルドが通ります)

原因の特定までに至らなかったのですが、今後のバージョンアップの参考になればと思い報告させていただきます 🙇

IndexOutOfRangeException: Index was outside the bounds of the array. VContainer.Internal.CappedArrayPool

Hello! I am trying to register class that has inheritance chain from several generic classes, like:

public ISomeInterface<T>{

}

public abstract class Base<T>: ISomeInterface<T>{

}

public abstract class AnotherBase<T>: Base<T>{
   private readonly SomeDependency _dep;

   protected AnotherBase(SomeDependency dep){
      _dep = dep;
   }
}

public class ActualClass: AnotherBase<ActualGenericClass>
{
   public ActualClass(SomeDependency dep): base(dep){
   }
}

SomeDependency is a ScriptableObject that is registered like this with builder.RegisterInstance(_dep);.
The next line is builder.Register<ActualClass>(Lifetime.Singleton);

And that gives me that error on container resolve:

IndexOutOfRangeException: Index was outside the bounds of the array.
VContainer.Internal.CappedArrayPool`1[T].Rent (System.Int32 length) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/CappedArrayPool.cs:51)
VContainer.Internal.ReflectionInjector.CreateInstance (VContainer.IObjectResolver resolver, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/ReflectionInjector.cs:31)
VContainer.Internal.Registration.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/Registration.cs:44)
VContainer.Container+<>c__DisplayClass4_0.<.ctor>b__1 () (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:132)
System.Lazy`1[T].CreateValue () (at <9577ac7a62ef43179789031239ba8798>:0)
System.Lazy`1[T].LazyInitValue () (at <9577ac7a62ef43179789031239ba8798>:0)
System.Lazy`1[T].get_Value () (at <9577ac7a62ef43179789031239ba8798>:0)
VContainer.Container.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:152)
VContainer.Container.Resolve (System.Type type) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:140)
VContainer.IObjectResolverExtensions.ResolveOrParameter (VContainer.IObjectResolver resolver, System.Type parameterType, System.String parameterName, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/IObjectResolverExtensions.cs:30)
VContainer.Internal.ReflectionInjector.CreateInstance (VContainer.IObjectResolver resolver, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/ReflectionInjector.cs:39)
VContainer.Internal.Registration.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/Registration.cs:44)
VContainer.Container.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:150)
VContainer.Internal.CollectionRegistration.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/Registration.cs:92)
VContainer.Container.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:150)
VContainer.Container.Resolve (System.Type type) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:140)
VContainer.IObjectResolverExtensions.ResolveOrParameter (VContainer.IObjectResolver resolver, System.Type parameterType, System.String parameterName, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/IObjectResolverExtensions.cs:30)
VContainer.Internal.ReflectionInjector.CreateInstance (VContainer.IObjectResolver resolver, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/ReflectionInjector.cs:39)
VContainer.Internal.Registration.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/Registration.cs:44)
VContainer.Container+<>c__DisplayClass4_0.<.ctor>b__1 () (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:132)
System.Lazy`1[T].CreateValue () (at <9577ac7a62ef43179789031239ba8798>:0)
System.Lazy`1[T].LazyInitValue () (at <9577ac7a62ef43179789031239ba8798>:0)
System.Lazy`1[T].get_Value () (at <9577ac7a62ef43179789031239ba8798>:0)
VContainer.Container.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:152)
VContainer.ScopedContainer.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:68)
VContainer.ScopedContainer.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:74)
VContainer.ScopedContainer.Resolve (System.Type type) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:55)
VContainer.IObjectResolverExtensions.ResolveOrParameter (VContainer.IObjectResolver resolver, System.Type parameterType, System.String parameterName, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/IObjectResolverExtensions.cs:30)
VContainer.Internal.ReflectionInjector.CreateInstance (VContainer.IObjectResolver resolver, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/ReflectionInjector.cs:39)
VContainer.Internal.Registration.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/Registration.cs:44)
VContainer.ScopedContainer+<>c__DisplayClass10_0.<.ctor>b__1 () (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:48)
System.Lazy`1[T].CreateValue () (at <9577ac7a62ef43179789031239ba8798>:0)
System.Lazy`1[T].LazyInitValue () (at <9577ac7a62ef43179789031239ba8798>:0)
System.Lazy`1[T].get_Value () (at <9577ac7a62ef43179789031239ba8798>:0)
VContainer.ScopedContainer.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:78)
VContainer.ScopedContainer.Resolve (System.Type type) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:55)
VContainer.IObjectResolverExtensions.ResolveOrParameter (VContainer.IObjectResolver resolver, System.Type parameterType, System.String parameterName, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/IObjectResolverExtensions.cs:30)
VContainer.Internal.ReflectionInjector.InjectMethods (System.Object obj, VContainer.IObjectResolver resolver, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/ReflectionInjector.cs:99)
VContainer.Internal.ReflectionInjector.Inject (System.Object instance, VContainer.IObjectResolver resolver, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/ReflectionInjector.cs:23)
VContainer.Internal.ReflectionInjector.CreateInstance (VContainer.IObjectResolver resolver, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/ReflectionInjector.cs:50)
VContainer.Internal.Registration.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/Registration.cs:44)
VContainer.ScopedContainer+<>c__DisplayClass10_0.<.ctor>b__1 () (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:48)
System.Lazy`1[T].CreateValue () (at <9577ac7a62ef43179789031239ba8798>:0)
System.Lazy`1[T].LazyInitValue () (at <9577ac7a62ef43179789031239ba8798>:0)
System.Lazy`1[T].get_Value () (at <9577ac7a62ef43179789031239ba8798>:0)
VContainer.ScopedContainer.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:78)
VContainer.Internal.CollectionRegistration.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Internal/Registration.cs:92)
VContainer.ScopedContainer.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:63)
VContainer.ScopedContainer.Resolve (System.Type type) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Container.cs:55)
VContainer.IObjectResolverExtensions.Resolve[T] (VContainer.IObjectResolver resolver) (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/IObjectResolverExtensions.cs:8)
VContainer.Unity.LifetimeScope.ActivateEntryPoints () (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Unity/LifetimeScope.cs:264)
VContainer.Unity.LifetimeScope.Build () (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Unity/LifetimeScope.cs:162)
VContainer.Unity.LifetimeScope.Awake () (at Library/PackageCache/jp.hadashikick.vcontainer@8fd4963749/Runtime/Unity/LifetimeScope.cs:122)

Is it because of that inheritance chain with generics? How to avoid that error if I still want to use that generic base classes?

How to resolve dependencies in non-registered class

Hello! I've been playing with VContainer, and i can't find our how to make one thing.

I have some MonoBehaviours "presenters" that inserted into prefab and they need their model dependency. What is the proper way to do that? It there a way to inject dependencies into current class?

EDIT: I should add that in this is basically to support some legacy code. Currently i think best way it to save main LifetimeScope to some global variable and resolve using Lazy.

フィールド代入処理最適化の提案

Unityには、FieldInfo.SetValueと同一の処理を数倍高速に実行できる UnsafeUtility.CopyObjectAddressToPtr という機能があります。
もし可能であれば、利用してみるのはいかがでしょうか?

例えば、このように使います。このコードの UnsafeFieldInfo.SetValueFieldInfo.SetValue よりも高速になることをご確認ください。

readonly struct UnsafeFieldInfo {
	public readonly Type fieldType;
	readonly int offset;

	public UnsafeFieldInfo(FieldInfo fieldInfo) {
		fieldType = fieldInfo.FieldType;
		offset = UnsafeUtility.GetFieldOffset(fieldInfo);
	}

	public unsafe void SetValue(object target, object value) {
		if (target == null) { return; }
		var targetPtr = UnsafeUtility.PinGCObjectAndGetAddress(target, out ulong targetHandle);
		UnsafeUtility.CopyObjectAddressToPtr(value, (byte*)targetPtr + offset);
		UnsafeUtility.ReleaseGCObject(targetHandle);
	}
}

なお、PropertyInfoにはこの方法は使えないと思われます。

CI broken

Test action

  • Run Unity test runner with some unity versions.

Release action

  • Fix to upload artifact

guid is missing

VContainer/Assets/VContainer/Runtime/VContainer.asmdef.metaがignoreされているようなので、
VContainer/Assets/VContainer/Editor/VContainer.Editor.asmdefと
VContainer/Assets/VContainer/Tests/VContainer.Tests.asmdefに登録されているguidが参照できないようです。

Feature to edit the IContainerBuilder

It may be useful to be able to replace the registered items later 🤔
Perhaps we can meet the #157 requirements.

builder.TryGet<IFoo>(out var registrationBuilder);
builder.Replace(registrationBuilder, new NewFooRegistrationBuilder(..))

register multiple services, which are used?

builder.Register<IFoo, Foo>();
builder.Register<IFoo, Bar>();

builder.Build().Resolver<IFoo>(); // which type?

Is this behavior undefined? First or Last?

Microsoft.Extensions.DependencyInjection uses Last registered.
This is useful for overriding arbitrarily after a plugin has registered.

LifetimeScope 派生クラスと Script Execution Order について

LifetimeScope のインスペクターでは Auto Inject Game Objects を設定することができ、
実行時設定した GameObject 以下の MonoBehaviour (※) へ inject できるようになっています。

LifetimeScope 派生クラスでこの Auto Inject Game Objects 機能を使用してみたところ、実行時に※への injection が起こるタイミングでは既に※のAwake() や OnEnable() が実行済みであることがありました。Auto Inject Game Objects を利用した injection は、シーン中の他のコンポーネントの Awake() や OnEnable() が実行されるよりも前に起こると思い込んでいたのでこの結果は意外でした。

これは LifetimeScope 派生クラスと※の Script Execution Order が何れもデフォルト(=0)であり、どちらの Awake() が先に実行されるかが決まっていないためだと思われます。実際、LifetimeScope 派生クラスの Script Execution Order を -9999 に設定したところ、※のAwake()が実行される前に injection が起こり、意図通りの動作となりました。

  • LifetimeScope 派生クラスが(Script Execution Order の意味で)なるべく素早く実行されるよう実装されているとありがたいです。
  • あるいはそれが無理でも、ドキュメントに Script Execution Order に関する記述があるとありがたいです。

なお、Zenject では Zenject.SceneContext の Script Execution Order は -9999 に設定されており、injection はシーン中の他のコンポーネントの Awake() や OnEnable() が実行されるようにも前に起こりますが、このことが私の思い込みの原因であったと思います。

Decorator support?

Scrutor library adds a cool decorator feature for Microsoft.Extensions.DependencyInjection. Is it possible to provide a similar thing here?

https://github.com/khellang/Scrutor

builder.Register<IPictureRepository, PictureRepository>();
builder.Decorate<IPictureRepository, CachingPictureRepository>();
builder.Decorate<IPictureRepository, LoggingPictureRepository>();

// Resolve<IPictureRepository> would resolve LoggingPictureRepository with this hierarchy of decoration
// - LoggingPictureRepository
// | - CachingPictureRepository
//   | - PictureRepository

Reverse injection order

ReflectionInjector now injects Methods, Properties then Fields.
Would it be safer to reverse order? In that case Methods are injected last and can refer to other injectables. By the way Properties setters will availabled to refer to injectable Fields.

As I understand Properties/Fields injection means optional dependency, also Method injection is like constructor mean entry point of initialization. So in injected method we can figure out which optional dependencies are resolved.

[Inject] method called twice when registering a monoBehaviour present in the scene.

I have an internal ClientInput class implementing MonoBehaviour in my client scene, present in the hierarchy on startup.

The way I pass down its dependencies is via the following method:

[Inject]
internal void Construct(InputCaptureSettings settings)
{ ... }

The root LifetimeScope registers the instance present in the scene from a serialized field like so:

builder.RegisterComponent(_clientInput)
  .As<IClientInput>();

Just to understand how and when the dependencies are provided, I added a Debug.Log to the Construct method of ClientInput and it turns out that the method is called twice.

ClientInput isn't listed in the "auto inject gameobject" list of any scope.

Is there something I'm not doing correctly here or is it an unexpected behavior?

Version mismatch

Git tag: 0.2.0
package.json's version: 0.0.1

To fix: bump version, then re-tag 0.2.0.

To avoid it in the future, recommended readings:


The issue is detected by openupm build pipelines (right bottom "build issues" section). OpenUPM is an open-source UPM registry with automatic build pipelines.

RegisterComponentInHierarchy().UnderTransform()でinactiveなComponentが登録できない

以下のようにUnderTransformを使うと非アクティブなGameObjectについたComponentを登録できません。
UnderTransformを使わなければ非アクティブでも登録できるので一貫性がない動作になっています。

builder.RegisterComponentInHierarchy<TestMonoBehaviour>().UnderTransform(transform);
// Error: VContainerException: Component TestMonoBehaviour is not in the parent GameObject

原因としては以下のGetComponentInChildrenでtrueを指定していないためです。

component = parent.GetComponentInChildren(ImplementationType);

If a value is published in the parent scope using UniRx, it cannot be subscribed to in the child scope

概要

親LifetimeScope内でUniRxを用いて値を発行すると子LifetimeScope内でその値の購読ができません。
(子LifetimeScope内で発行された値は親LifetimeScope内で購読できるので問題ないのかもしれません。)

具体例

EntryPointでUniRxのOnNext(Unit.Default)をしてもChildEntryPointでSubscribeに値が流れてこない。

親子関係

GameLifetimeScope
                |
ChildLifetimeScope

コード

public class GameLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.RegisterEntryPoint<EntryPoint>();
        builder.Register<Foo>(Lifetime.Singleton).AsImplementedInterfaces();
    }
}

public class EntryPoint : IStartable
{
    private readonly IFoo _foo;

    public EntryPoint(IFoo foo)
    {
        _foo = foo;
    }
    public void Start()
    {
        _foo.Publish();
    }
}

public class Foo : IFoo
{
    public IObservable<Unit> Observable => _subject;
    private readonly Subject<Unit> _subject = new Subject<Unit>();
    public void Publish()
    {
        _subject.OnNext(Unit.Default);
        Debug.Log("FOO!");
    }
}

public interface IFoo
{
    IObservable<Unit> Observable { get; }
    void Publish();
}
public class ChildrenLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.RegisterEntryPoint<ChildEntryPoint>();
    }
}

public class ChildEntryPoint : IStartable, IDisposable
{
    private readonly IFoo _foo;
    private readonly CompositeDisposable _disposable = new CompositeDisposable();
    public ChildEntryPoint(IFoo foo)
    {
        _foo = foo;
    }
    public void Start()
    {
        _foo.Observable
            .Subscribe(_ =>  UnityEngine.Debug.Log("Observe:Foo"))
            .AddTo(_disposable);
    }

    public void Dispose()
    {
        _disposable?.Dispose();
    }
}

ログ

FOO!

Request: Add a IContainerBuilder.RegisterProvider method

I would like a way to more easily delegate resolving a type to another function or class. Here's my thoughts for a few new RegisterProvider methods. The idea is that when resolving a given type T, it would invoke the provider and inject the returned result. Unlike a Factory, a provider would be called at the time of resolution, whereas a factory is injected directly.

public static RegistrationBuilder RegisterProvider<T>(this IContainerBuilder builder, Func<T> provider) { }
public static RegistrationBuilder RegisterProvider<TParam1, T>(this IContainerBuilder builder, Func<TParam1, T> provider) { }
public static RegistrationBuilder RegisterProvider<T>(this IContainerBuilder builder, Func<IObjectResolver, T> provider) { }
public static RegistrationBuilder RegisterProvider<T>(this IContainerBuilder builder, IProvider<T> provider) { }

Here's a simple example of how it would be used

Container:

protected override void Configure(IContainerBuilder builder)
{
    // Example 1: Super basic, basically equivalent to Lifetime.Transient but worse
    builder.RegisterProvider(() => new Foo());

    // Example 2:
    builder.Register<IMyService, MyServiceImpl>();
    // Delegating resolution of `Foo` to `IMyService`
    builder.RegisterProvider<IMyService, Foo>(myService => myService.ProvideFoo());
    // Or
    builder.RegisterProvider<Foo>(resolver => resolver.Resolve<IMyService>().ProvideFoo());
}

Consumer:

public class Bar
{
    // `Foo` is provided by provider specified above
    public Bar(Foo myFoo)
    {
        myFoo.DoThing();
    }
}

Maybe there is already a way of doing this sort of thing, but I haven't been able to find a good way to do it.

Semi-Transient lifetime of entry points

I faced a case where ITickable should be resolved in Transient way.
I have registration

builder.RegisterEntryPoint<ComboCounter>(Lifetime.Transient).AsSelf();

So each spawned ComboCounter is resolved but ticks are executed for other instances, which are created as ITickable for EntryPointDispatcher.
I admit the logic of this behavior. But ITickable and other entry points are treated as simple way to integrate player loop logic into C# class, however user fated to build their own player loop binding in that case.

Would it be a good decision to execute entry points only for instances that Transient resolved without entry point interfaces?

TypeAnalyzer.Analyze throws on enum

I'm trying to Inject enum Place value. So I registered it as builder.RegisterInstance(place).As(typeof(Place)).
But it throws at TypeAnalyzer.Analyze

            if (injectConstructor == null)
            {
#if UNITY_2018_4_OR_NEWER
                // It seems that Unity sometimes strips the constructor of Component at build time.
                // In that case, allow null.
                if (!type.IsSubclassOf(typeof(UnityEngine.Component)))
#endif
                    throw new VContainerException(type, $"Type does not found injectable constructor, type: {type.Name}");
            }

with stacktrace:

VContainer.Internal.TypeAnalyzer.Analyze (System.Type type) (at Library/PackageCache/[email protected]/Runtime/Internal/TypeAnalyzer.cs:130)
System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) (at <695d1cc93cca45069c528c15c9fdd749>:0)
VContainer.Internal.TypeAnalyzer.AnalyzeWithCache (System.Type type) (at Library/PackageCache/[email protected]/Runtime/Internal/TypeAnalyzer.cs:87)
VContainer.Internal.ReflectionInjector.Build (System.Type type) (at Library/PackageCache/[email protected]/Runtime/Internal/ReflectionInjector.cs:10)
VContainer.Internal.InjectorCache+<>c__DisplayClass1_0.<GetOrBuild>b__0 (System.Type type1) (at Library/PackageCache/[email protected]/Runtime/Internal/InjectorCache.cs:21)
System.Collections.Concurrent.ConcurrentDictionary`2[TKey,TValue].GetOrAdd (TKey key, System.Func`2[T,TResult] valueFactory) (at <695d1cc93cca45069c528c15c9fdd749>:0)
VContainer.Internal.InjectorCache.GetOrBuild (System.Type type) (at Library/PackageCache/[email protected]/Runtime/Internal/InjectorCache.cs:13)
VContainer.RegistrationBuilder.Build () (at Library/PackageCache/[email protected]/Runtime/RegistrationBuilder.cs:34)
VContainer.ContainerBuilder.BuildRegistrations () (at Library/PackageCache/[email protected]/Runtime/ContainerBuilder.cs:116)
VContainer.ScopedContainerBuilder.BuildScope () (at Library/PackageCache/[email protected]/Runtime/ContainerBuilder.cs:36)
VContainer.ScopedContainer.CreateScope (System.Action`1[T] installation) (at Library/PackageCache/[email protected]/Runtime/Container.cs:88)

UnityEditorでの実行後にReflectionTypeLoadExceptionが発生する

Windows 10
Unity 2020.3
VContainer.1.6.0
MagicOnion.Client.Unity v4.1.2

起動時に放置していても問題ないのですが、UnityEditor上で一度Sceneを実行したあとに停止し、そのまま放置しておくと一定間隔ごとに例外が発生し続けています。

ParentReferencePropertyDrawer#GetAllTypeNamesassembly.GetTypesで例外が発生してしまいます。

public sealed class ParentReferencePropertyDrawer : PropertyDrawer
{
static string[] GetAllTypeNames()
{
var result = new List<string> { "None" };
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(typeof(LifetimeScope)))
{
result.Add(type.FullName);
}
}

例外が発生するとLifetimeScopeを貼っ付けてるオブジェクトのインスペクタが正しく表示されないようです。

  • 例外発生前
    image
  • 例外発生後
    image

また、MagicOnionとも関係しているようなのですが、VContainer側の処理の対応になるのかMagicOnion側か、もしくは私がなにかトチってるかが判別出来なかったため、こちらに記載させていただきました。

  • 例外発生直前にassembly.CodeBaseで取得した値
    • file:///D:/PATH/TO/Unity/Library/ScriptAssemblies/MagicOnion.Client.dll
  • 例外発生直前にassembly.FullNameで取得した値
    • MagicOnion.Client, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
  • スタックトレース
ReflectionTypeLoadException: Exception of type 'System.Reflection.ReflectionTypeLoadException' was thrown.
System.Reflection.Assembly.GetTypes () (at <eae584ce26bc40229c1b1aa476bfa589>:0)
VContainer.Editor.ParentReferencePropertyDrawer.GetAllTypeNames () (at Library/PackageCache/jp.hadashikick.vcontainer@e17b3fb9e9/Editor/ParentReferencePropertyDrawer.cs:18)
VContainer.Editor.ParentReferencePropertyDrawer.OnGUI (UnityEngine.Rect rect, UnityEditor.SerializedProperty prop, UnityEngine.GUIContent label) (at Library/PackageCache/jp.hadashikick.vcontainer@e17b3fb9e9/Editor/ParentReferencePropertyDrawer.cs:38)
UnityEditor.PropertyDrawer.OnGUISafe (UnityEngine.Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label) (at <50f55621a2ca4f31a35283e2979a8bf5>:0)
UnityEditor.PropertyHandler.OnGUI (UnityEngine.Rect position, UnityEditor.SerializedProperty property, UnityEngine.GUIContent label, System.Boolean includeChildren, UnityEngine.Rect visibleArea) (at <50f55621a2ca4f31a35283e2979a8bf5>:0)
UnityEditor.GenericInspector.OnOptimizedInspectorGUI (UnityEngine.Rect contentRect) (at <50f55621a2ca4f31a35283e2979a8bf5>:0)
UnityEditor.UIElements.InspectorElement+<>c__DisplayClass59_0.<CreateIMGUIInspectorFromEditor>b__0 () (at <1d96ce257f0e45ff836d157d33fd933d>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)

試したこと

  • Menu->Assets->Reimport All
  • Libraryディレクトリの削除

Errors when installing some Unity packages

Repro steps:

  1. Install VContainer from OpenUPM
  2. Install Package Development from Unity Registry
GUID [1eb7e6f92b1d7d64ba0a48ea751728f3] for asset 'Packages/nuget.mono-cecil/CHANGELOG.md' conflicts with:
  'Packages/com.unity.nuget.mono-cecil/CHANGELOG.md' (current owner)
We can't assign a new GUID because the asset is in an immutable folder. The asset will be ignored.

support for dynamic objects / factories and generic unconstructed types

Hey, VContainer looks great but looking at the docs it seems it doesn’t currently support spawning of objects at runtime via Factories, is that the case? Same question for unconstructed generic types: for example is there a way to bind all types that implement interface IEventHandler from specified Assembly?

Resolve error with SceneManager.LoadScene (not Async)

when using:

using (LifetimeScope.EnqueueParent(parent))
{
    await SceneManager.LoadSceneAsync("...", LoadSceneMode.Additive);
}

things are resolved correctly in child container from parent container but in case of:

using (LifetimeScope.EnqueueParent(parent))
{
    SceneManager.LoadScene("...", LoadSceneMode.Additive);
}

parent container is not configured properly

A typo in the documents?

I think the argument is also a concrete type because it registers a concrete type.

diff --git a/README.md b/README.md
index 955667e..5231ebe 100644
--- a/README.md
+++ b/README.md
@@ -436,7 +436,7 @@ It can resolve like this:
 ```csharp
 class ClassA
 {
-    public ClassA(IServiceA serviceA) { /* ... */ }
+    public ClassA(ServiceA serviceA) { /* ... */ }
 }
 ```

Compatibility with DOTS/ECS?

Hey there,
I was thinking of trying this out and as I was reading the instructions I saw it had playerloop integration, which made me think it would be a good idea to ask if you happen to know if this is compatible with DOTS/ECS?

Thanks,
-MH

Proposal: Add virtual LifetimeScope.OnAfterBuild(IObjectResolver)

I would like to write the process after IContainerBuilder is built as follows.

public class CustomLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
    }

    // I want this virtual method!!!
    protected override void OnAfterBuild(IObjectResolver resolver)
    {
        resolver.Inject(obj);
    }
}

I can do the same with builder.RegisterBuildCallback, but it is hard to understand at first glance.
I think it will be easier to understand if we can standardize how to write as shown above.

Request: Register Named Dependency

Sometimes you might have multiple instances that could collide and it would be useful to be able to distinguish between them when resolving.

For instance:

builder.Register<Logger>(name: "StdOut", Lifetime.Singleton);
builder.Register<Logger>(name: "StdErr", Lifetime.Singleton);

A consumer could then specify which named logger they want injected:

class Foo 
{
    Foo([InjectNamed("StdOut")] Logger logger) { }
}

// or both!
class Bar
{
    Bar([InjectNamed("StdOut")] Logger stdLogger, [InjectNamed("StdErr")] Logger errLogger) { }
}

Can also be used to resolve primitives which could then be resolved throughout the container without needing to specify a WithParameter for every case where it is used:

builder.RegisterInstance<string>("https://www.my-url.com", name: "MyUrl");

[Zenject] (IMemory)Pool support

Has this library (or will it have) an alternative to Zenject's IMemoryPool?

It's a question not a feature request. If it's not in this library it's fine because there are plenty libraries for this. I'd love to see this in some kind of "we do not support" section in the docs :)

Not able to resolve interface of `LifetimeScope.Single` in child scope

version: 1.7.0
unity: 2020.3.1f1

using UnityEngine;
using VContainer;

public interface IFoo {}
public class Foo : IFoo {}

public interface IBar {}
public class Bar : IBar
{
    public Bar(IFoo _) {}
}

public class TestScope : MonoBehaviour
{
    void Awake()
    {
        var builder = new ContainerBuilder();
        var container = builder.Build();
        container.CreateScope(b =>
        {
            b.Register<Foo>(Lifetime.Singleton).AsImplementedInterfaces();
            b.Register<Bar>(Lifetime.Singleton).AsImplementedInterfaces();
            b.RegisterBuildCallback(c => c.Resolve<IBar>()); // error: VContainerException: Failed to resolve Bar : No such registration of type: IFoo
        });
    }
}
VContainerException: Failed to resolve Bar : No such registration of type: IFoo
VContainer.Internal.ReflectionInjector.CreateInstance (VContainer.IObjectResolver resolver, System.Collections.Generic.IReadOnlyList`1[T] parameters) (at Library/PackageCache/[email protected]/Runtime/Internal/ReflectionInjector.cs:46)
VContainer.Internal.Registration.SpawnInstance (VContainer.IObjectResolver resolver) (at Library/PackageCache/[email protected]/Runtime/Internal/Registration.cs:44)
VContainer.Container+<>c__DisplayClass5_0.<.ctor>b__1 () (at Library/PackageCache/[email protected]/Runtime/Container.cs:152)
System.Lazy`1[T].CreateValue () (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Lazy`1[T].LazyInitValue () (at <eae584ce26bc40229c1b1aa476bfa589>:0)
System.Lazy`1[T].get_Value () (at <eae584ce26bc40229c1b1aa476bfa589>:0)
VContainer.Container.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/[email protected]/Runtime/Container.cs:174)
VContainer.ScopedContainer.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/[email protected]/Runtime/Container.cs:69)
VContainer.ScopedContainer.Resolve (VContainer.IRegistration registration) (at Library/PackageCache/[email protected]/Runtime/Container.cs:72)
VContainer.ScopedContainer.Resolve (System.Type type) (at Library/PackageCache/[email protected]/Runtime/Container.cs:57)
VContainer.IObjectResolverExtensions.Resolve[T] (VContainer.IObjectResolver resolver) (at Library/PackageCache/[email protected]/Runtime/IObjectResolverExtensions.cs:8)
TestScope+<>c.<Awake>b__0_1 (VContainer.IObjectResolver c) (at Assets/TestScope.cs:23)
VContainer.ContainerBuilder.EmitCallbacks (VContainer.IObjectResolver container, System.Collections.Generic.IEnumerable`1[T] callbacks) (at Library/PackageCache/[email protected]/Runtime/ContainerBuilder.cs:158)
VContainer.ScopedContainerBuilder.BuildScope () (at Library/PackageCache/[email protected]/Runtime/ContainerBuilder.cs:39)
VContainer.ScopedContainer.CreateScope (System.Action`1[T] installation) (at Library/PackageCache/[email protected]/Runtime/Container.cs:88)
VContainer.Container.CreateScope (System.Action`1[T] installation) (at Library/PackageCache/[email protected]/Runtime/Container.cs:189)
TestScope.Awake () (at Assets/TestScope.cs:19)

Unity 2020.2.0f1 incompatible

Hello! Upgraded to latest official (non-beta) unity release and have following error on startup:

ArgumentException: UnityEngine.PlayerLoop.EarlyUpdate+ScriptRunDelayedStartupFrame not in system Initialization UnityEngine.PlayerLoop.Initialization
VContainer.Unity.PlayerLoopHelper.InsertSubsystem (UnityEngine.LowLevel.PlayerLoopSystem& parentSystem, System.Type before, UnityEngine.LowLevel.PlayerLoopSystem newSystem, UnityEngine.LowLevel.PlayerLoopSystem newPostSystem) (at Library/PackageCache/jp.hadashikick.vcontainer@16f243a128/Runtime/Unity/PlayerLoopHelper.cs:180)
VContainer.Unity.PlayerLoopHelper.Initialize () (at Library/PackageCache/jp.hadashikick.vcontainer@16f243a128/Runtime/Unity/PlayerLoopHelper.cs:72)
VContainer.Unity.LifetimeScope.ActivateEntryPoints () (at Library/PackageCache/jp.hadashikick.vcontainer@16f243a128/Runtime/Unity/LifetimeScope.cs:290)
VContainer.Unity.LifetimeScope.Build () (at Library/PackageCache/jp.hadashikick.vcontainer@16f243a128/Runtime/Unity/LifetimeScope.cs:175)
VContainer.Unity.LifetimeScope.GetRuntimeParent () (at Library/PackageCache/jp.hadashikick.vcontainer@16f243a128/Runtime/Unity/LifetimeScope.cs:266)
VContainer.Unity.LifetimeScope.Awake () (at Library/PackageCache/jp.hadashikick.vcontainer@16f243a128/Runtime/Unity/LifetimeScope.cs:131)

IStartableを実装しているとMagicOnionがクラッシュする

  • Windows 10
  • Unity 2020.3
  • VContainer.1.6.0
    • gitからmaster取得してます
    • d1fecbd 時点
  • MagicOnion.Client.Unity v4.1.2

下記の手順でMagicOnionがクラッシュします。
LifetimeScopeがSceneにない状態でMagicOnionの実行が出来る、複数回の起動でクラッシュしていないことは確認済みです。
(今回のサンプルだと実行は確認出来ません)

手順

  1. シーンにLifetimeScopeをつけたオブジェクトを置く
  2. UnityEditor上でSceneを実行し、停止
  3. 再度Sceneを実行
  • 今回は検証のためほぼ空のSceneで実行したのでVContainerによるものかなと
    image

読み込まれていると思われるスクリプト

  • GameLifetimeScope.cs
using VContainer;
using VContainer.Unity;

public class GameLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.Register<HelloWorldService>(Lifetime.Singleton);
        builder.RegisterEntryPoint<GamePresenter>(Lifetime.Singleton);
    }
}
  • HelloWorldService.cs
public class HelloWorldService
{
  // 読み込ませるだけなので処理なし
}
  • GamePresenter.cs
using VContainer.Unity;

public class GamePresenter : IStartable
{
    private readonly HelloWorldService _helloWorldService;

    public GamePresenter(HelloWorldService helloWorldService)
    {
        _helloWorldService = helloWorldService;
    }
    void IStartable.Start()
    {
        // 特に何もしない
    }
}

備考

GamePresenter.csからIStartableの実装を抜いた状態にするとクラッシュしなくなりました。
ただし、一度クラッシュするようになっているとUnity再起動するまで関係なくクラッシュし続けるようです。

- public class GamePresenter : IStartable
+ public class GamePresenter
{
    private readonly HelloWorldService _helloWorldService;

    public GamePresenter(HelloWorldService helloWorldService)
    {
        _helloWorldService = helloWorldService;
    }
-    void IStartable.Start()
-    {
-        // 特に何もしない
-    }
}

Unity Consoleに出力されたエラー

Error: Could not load signature of MagicOnion.ChannelExtensions:RegisterStreamingSubscription due to: Could not load file or assembly 'Grpc.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad' or one of its dependencies. assembly:Grpc.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad type:<unknown type> member:(null) signature:<none>

Error: Could not load signature of MagicOnion.MetadataExtensions:Get due to: Could not load file or assembly 'Grpc.Core.Api, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad' or one of its dependencies. assembly:Grpc.Core.Api, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad type:<unknown type> member:(null) signature:<none>
Unloading broken assembly Library/ScriptAssemblies/MagicOnion.Unity.dll, this assembly can cause crashes in the runtime
Unloading broken assembly Library/ScriptAssemblies/MagicOnion.Client.dll, this assembly can cause crashes in the runtime

Cannot create custom RegistrationBuilder

IContainerBuilder provides public Register(RegistrationBuilder) method which is completely useless given that all the constructors of RegistrationBuilder are internal. Taking this into account, there are two options:

  1. Change it to internal IContainerBuilder.Register(RegistrationBuilder)
  2. Make RegistrationBuilder more open for extension

IMO (2) is a better option since I've already got into a situation where a custom RegistrationBuilder would be useful.

Separate Scriptable Object installer

Hello! I am trying to create separate installer for ScriptableObject for RootLifetimeScope in VContainerSettings.
The way I am doing it is this:

 public class ScriptableObjectsInstaller : ScriptableObject, IInstaller
    {
        [SerializeField]
        private EncryptionSettings _encryptionSettings;

        public void Install(IContainerBuilder builder)
        {
            builder.RegisterInstance<AuthenticationStorage>(new AuthenticationStorage(_encryptionSettings));
        }
    }

And then in RootLifetimeScope:

 public class RootLifetimeScope : LifetimeScope
    {
        [SerializeField]
        private ScriptableObjectsInstaller _scriptableObjectsInstallers;

        protected override void Configure(IContainerBuilder builder)
        {
             Push(_scriptableObjectsInstallers);
        }
    }

The problem is that the method Install in ScriptableObjectsInstaller seems to be called several times, once for each LifetimeScope in scene. E.g. if I have 3 scenes additevely loaded, then it will be called 3 times.

Is it intended behaviour or bug?
If it's intented, then how to accomplish the behaviour I want? To be clear:
I don't want to bloat RootLifetimeScope with tons of references to different ScriptableObject, so I want to group them in separate installers and just "feed" them to RootLifetimeScope.

Can not resolve IObjectResolver itself

when using IObjectResolver directly, can not resolver IObjectResolver itself.

var builder = new ContainerBuilder(); 
var resolver = builder.Build();
var resolver2 = r.Resolve<IObjectResolver>(); // exception, not registered

I'm currently using the following code for unit testing.

public class VContainerTest
{
    [Test]
    public void VContainerTestSimplePasses()
    {
        var builder = new ContainerBuilder();
        builder.Register<MyClass>(Lifetime.Transient);

        var resolver = builder.Build();

        // exception, can not resolve IObjectResolver...
        var mc = resolver.Resolve<MyClass>();
    }
}
public class MyClass
{
    readonly IObjectResolver resolver;
    public MyClass(IObjectResolver resolver)
    {
        this.resolver = resolver;
    }
}

Do you have any workaround?

CodeGen is not working on Unity 2020.2 or later.

In 2020.2 and later, the behavior of ILPostProcessor seems to have changed.

  • Unity's API seems to be unavailable.
    • UnityEngine.Debug.Log throws MissingMethodException
    • AssetDataBase / PlayerSettings also throws.
  • Instance from ILPostProcessor is now always null.

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.