Giter VIP home page Giter VIP logo

strangeioc's Introduction

Strange: the IoC framework for Unity3D and C#

Current version: v1.0.0

Website: http://strangeioc.github.io/strangeioc/

Strange attractors create predictable patterns, often in chaotic systems.

Strange is a super-lightweight and highly extensible Inversion-of-Control (IoC) framework, written specifically for C# and Unity. We've validated Strange on web, standalone, and iOS, and Android.

It contains the following features, most of which are optional:

  • A core binding framework that pretty much lets you bind one or more of anything to one or more of anything else.
  • Dependency Injection
    • Map as singleton, value or factory (get a new instance each time you need one)
    • Name injections and/or supply specific implementations to specific consumer classes
    • Perform constructor or setter injection
    • Tag your preferred constructor
    • Tag a method to fire after construction
    • Inject into MonoBehaviours
    • Bind polymorphically (bind any or all of your interfaces to a single concrete class)
  • Reflection binding dramatically reduces overhead of employing reflectivity
  • Two shared event bus systems, EventDispatcher and Signals. Both allow you to:
    • Dispatch events to any point in your application
    • Map local events for local communication
    • Map events to Commands classes to separate business logic
    • EventDispatcher transmits data payloads as primitives or ValueObjects
    • Signals transmits data in bindable, type-safe parameters
  • MonoBehaviour mediation
    • Facilitate separation of a view from the application using it
    • Keep Unity-specific code isolated from the rest of the app
  • Optional MVCS (Model/View/Controller/Service) structure
  • Multiple contexts
    • Allow subcomponents (separate Scenes) to function on their own, or in the context of larger apps.
    • Allow communication between contexts.
  • Promises
    • Similar to Javascript Q-Promises, these help control flow and error handling
    • Promises also fit some common signal use cases much more cleanly!
  • Annotated 'Implicit' Bindings
  • Reduce boiler plate code written in your Context and Mediators!
  • JSON-driven bindings
  • Dynamically load your bindings at runtime!
  • Don't see what you need? The core binding framework is simple to extend. Build new Binders like:
    • A different type of dispatcher, like AS3-Signals <- WAIT A MOMENT! WE DID EXACTLY THAT!!!
    • An entity framework
    • A multi-loader

In addition to organizing your project into a sensible structure, Strange offers the following benefits:

  • Designed to play well with Unity3D. Also designed to play well without it.
  • Separate UnityEngine code from the rest of your app.
    • Improves portability
    • Improves unit testability
  • A common event bus makes information flow easy and highly decoupled. (Note: Unity's SendMessage method does this, of course, but it's dangerous as all get-out. I may write a whole article on just this topic at some point.)
  • The extensible binder really is amazing (a friend used to tell me "it's good to like your own cookin'"). The number of things you can accomplish with the tiny core framework would justify Strange all on its own.
  • Multiple contexts allow you to "bootstrap" subcomponents so they operate fine either on their own or as an integrated part. This can hugely speed up your development process and allow developers to work in isolation, then integrate in later stages of development.
  • Get rid of platform-specific #IF...#ELSE constructs in your code. IoC allows you to write whole concrete implementations correctly, then bind the ones you want to use at compile time or at run time. (As with other forms of binding, #IF...#ELSE clauses can be isolated into a single class and away from the rest of your code.)

Supported Versions/Platforms

Strange works with Unity 3.5+. Click here to see the full list of supported runtime platforms.

Acknowledgements

It is hard to adequately credit the creators of the open source Actionscript framework RobotLegs for their influence on the creation of StrangeIoC. While Strange is not a port of RobotLegs, the ensigns of that library are copiously reflected throughout this one. For their great service to my professional development, I offer that team my sincerest thanks. And a donut. Seriously, if you're ever in town, let me buy you a donut.

Kudos to Will Corwin for picking up a thrown-down gauntlet and writing the Signals and Implicit Bindings implementations.

I also need to thank and congratulate the folks at ThirdMotion who inexplicably gave me time to build Strange and license to open source it.

/**********************************************/ Copyright 2013 ThirdMotion, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.

strangeioc's People

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

strangeioc's Issues

Cannot inject object bound in parent context in the mediator of a chid context

(As you can tell from the last few days, I am going in hard on nested contexts)

I have a parent context, a child context, and a view monobehaviour all in nested gameobjects:

ParentContext
  > ChildContext 
    > View

In the parent context, I use the injection binder to bind a Model to a singleton instance, and make it cross-context:

injectionBinder.Bind<Model>().ToSingleton().CrossContext();

In a child context, I bind the view to a mediator. In the mediator, I attempt to inject the Model from the parent context:

[Inject]
public Model ModelInstance { get; set; }

The problem is that the mediator gets instantiated and injected when the child context awakes, which is before the parent context gets awoken, so it doesn't know how to inject Model.

I worked around this by injecting the injection binder itself into the mediator, and then pulling out the singleton instance myself when I need it later.

However it would be great if this Just Worked, or if there was a more standard pattern for doing this.

Is it possible to share a context between scenes?

In the docs the context root is always attached to the top game object in the scene. Does this mean that the context will be re initialized for every scene? What if you'd like some model to be a game wide singleton instead of a scene wide singleton. I think I might misunderstanding something in the docs...

Signals - recommended practice to override Context's Start method

According to your documentation on using signals, you recommend overriding your Context's Start method with a custom StartSignal.
Instead of the Start method, doesn't it make more sense to override the Launch method? The Launch method is where ContextEvent.START is dispatched from, so it seems to make sense that the StartSignal should be dispatched from it as well.

Startup Syntax

It seems odd that the 'true' parameter then still requires Start() to be explicitly called no? I'm not saying there isn't a reason for the current implementation, I'm saying its counter-intuitive.

CURRENT IMPLEMENTATION

        context = new MyFirstContext(this, true);
        context.Start ();

ALTERNATIVE POSSIBLE IMPLEMENTATION

        context = new MyFirstContext(this, false);
        context.Start (); //required.

and

        context = new MyFirstContext(this, true);
        //context.Start (); //not required.

FirstContext static value does not handle Scene Unloading/Loading

If loading/changing scenes the firstContext value could have already been set by a context which is not to be considered the "First Context". Reloading the same scene will result in a null contextView.

Proposed solution: Test for a null contextView and replace firstContext upon instantiating any context and finding that the firstContext.contextView == null

Disabled GameObjects

Hi!

I have problem with disabled GameObjects and injections. I have attached View to my GameObject and created binding to Mediator. I click on my GameObject and disable it in inspector. Then I click play and I see log from method OnRegister and in inspector mediator appears. I have only one GameObject with this view on the scene. When I remove it from scene I see that any injections are not created.

Where can be a problem?

Sebastian

toValue() doesnt work as expected

in context:
injector.Bind().ToValue(new WhiteElephant());

In Class XY:
[Inject]
IInterface blablabla;

When injecting game crashes because Strange tries to constructor inject the instance assigned with ToValue(). I dont know, maybe it's trying to create a new instance.

I should point out that I'm manually injecting my XY instance:
injector.Inject(anXYInstance);

To get the behaviour I expected I had to Bind like this:
injector.Bind().ToValue(new WhiteElephant()).ToSingleton().ToInject(false);

Strange IoC running within UnityEditor?

Hi, Are there any gotchas that I should be aware of in trying to get Strange IoC running within the UnityEditor at edit time, for use in an editor extension? I'd like explore using it to help manage some of my editor windows. Any thoughts would be appreciated..

Thanks,
Jim

ToValue(obj) uses type of obj instead of obj

Seems that

var cSample = new ComplexConstructorSample (5, 5);
injectionBinder.Bind<IComplexSample> ().ToValue (cSample).ToSingleton ();

throws the following error on injecting it somewhere:

ArgumentNullException: Argument cannot be null.
Parameter name: key
System.Collections.Generic.Dictionary`2[System.Object,System.Collections.Generic.Dictionary`2[System.Object,strange.framework.api.IBinding]].ContainsKey (System.Object key) (at /Applications/buildAgent/work/b59ae78cff80e584/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:458)
strange.framework.impl.Binder.GetBinding (System.Object key, System.Object name) (at Assets/scripts/strange/framework/impl/Binder.cs:95)
strange.framework.impl.Binder.GetBinding (System.Object key) (at Assets/scripts/strange/framework/impl/Binder.cs:80)
strange.extensions.reflector.impl.ReflectionBinder.Get (System.Type type) (at Assets/scripts/strange/extensions/reflector/impl/ReflectionBinder.cs:48)
strange.extensions.injector.impl.Injector.Instantiate (IInjectionBinding binding) (at Assets/scripts/strange/extensions/injector/impl/Injector.cs:61)
strange.extensions.injector.impl.Injector.getValueInjection (System.Type t, System.Object name, System.Object target) (at Assets/scripts/strange/extensions/injector/impl/Injector.cs:185)
strange.extensions.injector.impl.Injector.performSetterInjection (System.Object target, IReflectedClass reflection) (at Assets/scripts/strange/extensions/injector/impl/Injector.cs:154)
strange.extensions.injector.impl.Injector.Inject (System.Object target, Boolean attemptConstructorInjection) (at Assets/scripts/strange/extensions/injector/impl/Injector.cs:114)
strange.extensions.injector.impl.Injector.Instantiate (IInjectionBinding binding) (at Assets/scripts/strange/extensions/injector/impl/Injector.cs:78)
strange.extensions.injector.impl.InjectionBinder.GetInstance (System.Type key, System.Object name) (at Assets/scripts/strange/extensions/injector/impl/InjectionBinder.cs:60)
strange.extensions.injector.impl.InjectionBinder.GetInstance (System.Type key) (at Assets/scripts/strange/extensions/injector/impl/InjectionBinder.cs:50)
strange.extensions.injector.impl.InjectionBinder.GetInstance[ICommand] () (at Assets/scripts/strange/extensions/injector/impl/InjectionBinder.cs:66)
strange.extensions.command.impl.EventCommandBinder.createCommand (System.Object cmd, System.Object data) (at Assets/scripts/strange/extensions/command/impl/EventCommandBinder.cs:43)
strange.extensions.command.impl.CommandBinder.invokeCommand (System.Type cmd, ICommandBinding binding, System.Object data, Int32 depth) (at Assets/scripts/strange/extensions/command/impl/CommandBinder.cs:100)
strange.extensions.command.impl.CommandBinder.ReactTo (System.Object trigger, System.Object data) (at Assets/scripts/strange/extensions/command/impl/CommandBinder.cs:93)
strange.extensions.command.impl.CommandBinder.Trigger (System.Object key, System.Object data) (at Assets/scripts/strange/extensions/command/impl/CommandBinder.cs:159)
strange.extensions.dispatcher.eventdispatcher.impl.EventDispatcher.Dispatch (System.Object eventType, System.Object data) (at Assets/scripts/strange/extensions/dispatcher/eventdispatcher/impl/EventDispatcher.cs:105)
strange.extensions.dispatcher.eventdispatcher.impl.EventDispatcher.Dispatch (System.Object eventType) (at Assets/scripts/strange/extensions/dispatcher/eventdispatcher/impl/EventDispatcher.cs:68)
strange.extensions.context.impl.MVCSContext.Launch () (at Assets/scripts/strange/extensions/context/impl/MVCSContext.cs:285)

From debugging the problem it seems that the Type of the given object is taken instead of the object itself. It at least tries to construct its own object once. Which fails in this case.

... using Unity 4.2 and current version from Unity Store (June 30, 2013). I have a small sample Unity project if you need one. Can't attach it here.

Classes bound as singletons cannot use constructor injection

I LOVE this framework! But I'm having this issue:

Making the following changes to ExampleService.cs in the signals sample project causes errors. (Changes: comment out [Inject] on fulfillSignal and put it in the constructor instead). If ExampleService is not bound as ToSingleton(), no such error occurs.

    (...snip...)
    [Inject(ContextKeys.CONTEXT_VIEW)]
    public GameObject contextView{get;set;}

    //The interface demands this signal
    //[Inject]
    public FulfillWebServiceRequestSignal fulfillSignal{get;set;}

    private string url;

    public ExampleService (FulfillWebServiceRequestSignal fulfillSignalParam)
    {
        fulfillSignal = fulfillSignalParam;
    }

    public void Request(string url)
    {
        this.url = url;
    (...snip...)

RemoveContext can break EventDispatcher

Since RemoveContext removes the current Context's dispatcher from the triggerClients of the CrossContextDispatcher, it is possible to get an IndexOutOfRangeException in the process of removing a Context.

Some testing has confirmed this and a fix is pending.

Binder cannot fetch Bindings when the binder is in a conflicted state.

What could lead to this conflicted state?

I am getting the error on iOS device, but not in the editor.

I have added logging from the Binder class in the following 2 places:

  • registerNameConflict
  • clearConflict

On both the editor and the device I see 6 conflicts and 6 resolutions of type IEventDispatcher.

But after those logs on the device, I get several of the conflicted error logs and the app only partially functions.

Is this something inherent in strange's binding or am I creating the conflict?

Thanks

Implement pooling

Requirements:

  • Factory mappings should be arbitrarily poolable (at the moment, if a mapping isn't Singleton/Value, it generates infinitely).
  • Events & Commands should draw from a pool by default to avoid rapid object creation/GC.

A value binding should never construct/post-construct

From a thread on Google Groups:

I have an issue with value binding and post construct and I would like to know if the following behaviour is normal. Let's suppose I have this class:

public class A : IA
{
[PostConstruct]
public void Init() {}
}

and I bind an instance as a value:

IA a = new A();
injectionBinder.Bind().ToValue(a);

then I inject it in another class:

public class B
{
[Inject]
public IA A {get;set;}
}

Every time I instantiate an object with the class B, the PostConstruct method of class A is called when performing the setter injection.


Issue confirmed and fix in progress.

Exceptions in a command causes other listeners to not get event

in v.50 if an event threw an exception, a second event listening to the same message would not end up getting the message. While a simple try/catch around the command/execute with a release (and maybe an end sequence event?) in CommandBinder's "executeCommand" function seems like a trivial workaround for the issue, the correct fix may be somewhat different.

[question] binding service in parent context, to be available for binding in child context?

Let's say I have an RNG service. I want the same instance to be available everywhere in my game by default, but then in some places (say procedural generation) I want to replace the main service with another.

I've tried binding the RNG to a singleton in my main context, but child contexts then can't inject. I've tried putting it in the cross-context bridge, but the IBinding that the bridge uses doesn't let me ask for a singleton.

Finally I tried injecting the parent context into a child context, and looking for the binding to re-bind locally, but the injection didn't work. :(

Is this kind of thing possible?

Cannot bind to cross-context signal of parent context in nested context

I had this working with events, and have changed it over to signals.

I have two contexts, one nested in a child gameobject of the other.

Both contexts have the addCoreComponent override:

protected override void addCoreComponents()
{
    base.addCoreComponents();
    injectionBinder.Unbind<ICommandBinder>();
    injectionBinder.Bind<ICommandBinder>().To<SignalCommandBinder>().ToSingleton();
}

I have a simple parameterless signal:

public class StartGame : Signal
{
}

My parent context marks this as cross-context, as mentioned on the blog:

injectionBinder.Bind<StartGame>().ToSingleton().CrossContext();

My child context binds this signal to a command:

commandBinder.Bind<StartGame>().To<GenerateWorldCommand>();

Debug.Log() statements show that the signal is raised:

parentContext.dispatcher.Dispatch(new PombaSignals.StartGame());

But it never reaches the GenerateWorldCommand.

I had this working using the crossContextBridge and events.

[Discussion] Fetching the context dispatcher in legacy MonoBehaviours

I'm using strange in a small branch of new code in a large legacy codebase. To get the legacy code to call into the new code, I'd ideally like it to fetch the correct dispatcher and use it:

public class LegacyMonoBehaviour : MonoBehaviour {

    [Inject(Modules.FooModuleDispatcher)]
    public IDispatcher FooDispatcher { get; set; }

    public void Bar() { FooDispatcher.Dispatch(FooEvents.Bar); }
}

However this doesn't work because MonoBehaviours aren't created through injectionBinder.GetInstance<>(). I don't want to change the base class of this legacy code either, or move its position in the object hierarchy.

I can just make a singleton to store the Foo dispatcher, but it feels like there's a right way to do this. Is there a way for me to post-process a MonoBehaviour, maybe in its Awake() or Start(), to get the property injections completed? Should there be, or some other way of handling this? Feels like it would be a common use case.

Named Factory Binding always returns the same instance (like singleton)

Contrary to what's indicated in the documentation a binding along these lines is not a factory mapping:

injectionBinder.Bind<IEnemy>().To<Borg>().ToName(EnemyType.ADVANCED); injectionBinder.Bind<IEnemy>().To<Romulan>().ToName(EnemyType.BASIC);

instead, an [Inject(EnemyType.ADVANCED)]ed property or a GetInstance<IEnemy>(EnemyType.ADVANCED) call will always return the same instance of the target type.

We discussed this on twitter, and after doing some investigating I think it's a bug. Here is a project to reproduce it using the myfirstproject example included in strange:

https://dl.dropboxusercontent.com/u/595326/NamedInjectionSameInstanceSample.zip

Advice for using Strange with Mecanim

Hi there,

I'm looking at using Strange for an upcoming project, and I have some questions about how to use it with Mecanim. Specifically, I know that I will need one or more animated NPC characters, and I would like to use the Animator state machine systems in Unity for them since it's been tested and proven for me. The state machine/animator feels like it should be model level code to me, but since it's a component on a GameObject, doesn't that place it in view territory?

How do you recommend using Strange to handle this? My initial plan would be to duplicate the parameters used by the animator in the model. When these change, the mediator updates the view which in turn updates the animator state machine. The animator parameters would therefore mirror what's in the model. The downsides to this are of course the creation of two sets of parameters to be maintained, as well as always making sure the animator is in sync with the model. Is there a way for the model and the animator to directly reference each other without violating good separation of concern practices, or would it simply be a case of necessary exception? Have you done any work with integrating these systems?

These NPCs may also wind up using the NavMesh systems as well. Since I haven't done enough research on that, I don't have a specific question, but I am also curious if you have any advice on that front.

Thanks,

Andrew

Documentation/example fixes

This just in......

Hi. I'm an AS3 developer with RobotLegs experience. I'm diving into
Unity and I found StrageIoC. It looks really great and the
documentation is great too.

I found a few flaws in the documentation and sample project that I
thought you'd appreciate hearing about:

re: http://thirdmotion.github.io/strangeioc/TheBigStrangeHowTo.html

  1. The doc says, "When you open the scene in Unity you'll find a
    GameObject named “ContextView” but it's actually called, "ViewGO".

  2. When I tried to launch the app I got errors because the strange
    files weren't accessible by the code. I don't yet know how to point a
    project at external resources, so I had to copy them into my assets
    folder. Here's the error:
    Assets/scripts/multiplecontexts/game/GameContext.cs(24,15): error
    CS0234: The type or namespace name extensions' does not exist in the namespacestrange'. Are you missing an assembly reference?

  3. In StartCommand the doc shows a call to AddComponent without any parameters:
    go.AddComponent();

But, in the actual file you call it properly:
go.AddComponent();

Thanks for your fantastic work on an IoC framework for Unity.

[feature request] runtime warning when mediator bindings are inverted

Just spent half an hour debugging because I had this in my context:

mediationBinder.Bind<MyMediator>().To<MyView>();

...instead of:

mediationBinder.Bind<MyView>().To<MyMediator>();

The docs are clear on this, but it would be nice if the runtime threw a wobbly if you tried to bind the wrong way around.

Is there a way to use strangeioc from the git repo?

It is only straightforward to import strange from the unity asset store. How should it be done straight from the git repo?

My ideal workflow would have strangeioc as a git submodule in my own unity project.

Thanks.

Test Issue

This should go to github, not vendors.

"Live bindings"

@rfish Requested a way to update injections on-the-fly.

Use case
I have a binding. Say:

injectionBinder.Bind<ISocialService>().To<FacebookService>().ToSingleton();

If I toggle the service at runtime, I can do this:

injectionBinder.Unbind<ISocialService>();
injectionBinder.Bind<ISocialService>().To<TwitterService>().ToSingleton();

This works for all future injections, but what about places I've already injected? I'd like to be able to "live update" a pre-existing binding.

Proposal
The developer will mark a binding for live update:

injectionBinder.Bind<ISocialService>().To<FacebookService>().ToSingleton().Live();

The InjectionBinder (or the Injector itself) will track those marked bindings in a dictionary...

//key is the binding key. value is the target instance
Dictionary<object, WeakReference<object>>

...such that whenever the binding is rebound, the target instance is re-injected with the updated value.

Value-binding does not work: various Exceptions

injectionBinder.Bind<int>().ToValue(42); causes exceptions in multiple locations.
as does injectionBinder.Bind<IInjectionBinder>().ToValue(injectionBinder);

first:
when I call injectionBinder.ReflectAll () I get an InvalidCastException because the ReflectAll()method tries to cast the value (42) to Type.

second:
skipping ReflectAll() there's an ArgumentNullException:

ArgumentNullException: Argument cannot be null. Parameter name: key System.Collections.Generic.Dictionary2[System.Object,System.Collections.Generic.Dictionary2[System.Object,strange.framework.api.IBinding]].ContainsKey (System.Object key) (at /Applications/buildAgent/work/b59ae78cff80e584/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:458) strange.framework.impl.Binder.GetBinding (System.Object key, System.Object name) (at Assets/@AssetStore/strange/framework/impl/Binder.cs:105) strange.framework.impl.Binder.GetBinding (System.Object key) (at Assets/@AssetStore/strange/framework/impl/Binder.cs:80) strange.extensions.reflector.impl.ReflectionBinder.Get (System.Type type) (at Assets/@AssetStore/strange/extensions/reflector/impl/ReflectionBinder.cs:48) strange.extensions.injector.impl.Injector.Instantiate (IInjectionBinding binding) (at Assets/@AssetStore/strange/extensions/injector/impl/Injector.cs:77) strange.extensions.injector.impl.Injector.getValueInjection (System.Type t, System.Object name, System.Object target) (at Assets/@AssetStore/strange/extensions/injector/impl/Injector.cs:185) strange.extensions.injector.impl.Injector.performSetterInjection (System.Object target, IReflectedClass reflection) (at Assets/@AssetStore/strange/extensions/injector/impl/Injector.cs:170) strange.extensions.injector.impl.Injector.Inject (System.Object target, Boolean attemptConstructorInjection) (at Assets/@AssetStore/strange/extensions/injector/impl/Injector.cs:130) strange.extensions.mediation.impl.MediationBinder.injectViewAndChildren (IView view) (at Assets/@AssetStore/strange/extensions/mediation/impl/MediationBinder.cs:97) strange.extensions.mediation.impl.MediationBinder.Trigger (MediationEvent evt, IView view) (at Assets/@AssetStore/strange/extensions/mediation/impl/MediationBinder.cs:61) strange.extensions.context.impl.MVCSContext.AddView (System.Object view) (at Assets/@AssetStore/strange/extensions/context/impl/MVCSContext.cs:337) strange.extensions.mediation.impl.View.bubbleToContext (UnityEngine.MonoBehaviour view, Boolean toAdd, Boolean finalTry) (at Assets/@AssetStore/strange/extensions/mediation/impl/View.cs:99) strange.extensions.mediation.impl.View.Start () (at Assets/@AssetStore/strange/extensions/mediation/impl/View.cs:67)

It all seems to boil down to ToValue mappings being interpreted wrongly. As this happens with the MyFirstContext sample included I assume I am not doing anything wrong?

Any ideas?

Automated testing with Strange

I'm noticing that many of the files seem to have been created by Unity such that they're listed as requiring UnityEngine but aren't actually using it, but this raises the question of testing code built with Strange, especially automated tests.

One approach I've attempted so is to rename MVCSContext to UMVCSContext (the U being for Unity) as it depends on Unity libs and made a new MVCSContext which doesn't rely on Unity and from which UMVCSContext can derive. This allows me to set up tests which launch the Context & do binding to mock objects on setup,but it is an unsatisfying solution. Especially when the setup / Arrange (of AAA) seems to rely upon the [Unity] mediators generating the commands and when so much relevant game state is held within views.

At present, you can test up to the command level but not beyond -- not to the mediators which tend to be the ones actually firing the events / calling the commands. Aside from using another wrapping framework, such as Uniject ( https://github.com/banderous/Uniject/ ), what would you recommend to facilitate automated testing with Strange? It seems like the only thing which could reasonably be done is, for each game object, foreswear Unity's component system and provide a backing model accessed from the mediator and have every call go through commands with regards to those models. Again, unsatisfying.

Thoughts?

Bug at "multiple bindings to singleton" injection

Hi!

I've need a singletone service with multiple interfaces in my application:

IMapViewer <- IMapEditor <-Map

So I've used injection binding:

Bind<IMapViewer>().Bind<IMapEditor>().To<Map>().ToSingleton();

but when I called:

GetInstance<IMapEditor>() as IMapEditor;
GetInstance<IMapViewer>() as IMapViewer;

I've got two different instances of a Map. I think its not desired behaviour :)

map bindings when switching scenes

Hi,

I have a weird issue, and maybe I'm missing something, But my project consists of multiple scenes. Each scene has it's on context to map mediators and this works when I launch the scene. However the mediators are not registered when I load the same scene from my initial main scene.
The game objects to be mapped are not dynamically created. Am I missing something?

State Machine

Do you have a best practice for state machine integration?

I know Robotlegs had a state machine utility at one point. Would you look into making a state machine injector? Or if you just have suggestions on where to store states and logic in the typical MVC paradigm, that would help as well.

Thanks!

Binding 'lost' after Application.LoadLevel(Application.loadedLevel);

Hi,

I have deep experience with MVC in AS3, 1 year of Unity experience, and 1 week of StrangeIOC experience.

I'm experiencing a functional first run of my game, but upon restarting the game programatically using Application.LoadLevel(Application.loadedLevel), while it appears to be a 'clean' restart (nothing 'old' in memory which is to be expected), an important signal-to-command binding fails to work on the second time through.

Like any 'bug report' the fault could easily be mine, but I'm not even sure how I could INTENTIONALLY have the results be unique after a Application.LoadLevel(Application.loadedLevel) call, so I'm at a loss on how to debug.

Any thoughts?

-Sam

IMAGE: ATTACHED. Notice step #4 is missing after 'reload'
SOURCE: https://github.com/RivelloMultimediaConsulting/CodeSamplesPublic/tree/master/projects/UnityArchitectures_Bowling/6_Bowling_StrangIoC

bindinglostlevelreload_1_v1

-Sam

[feature request] error if developer attaches [Inject] to a private property

Just spent ten minutes stepping through the debugger, trying to figure out why my properties weren't being injected. Seems I had missed the public keyword on my property!

The report can be an exception, and it should list the type of the object containing the property, and the property name. One possible phrasing:

Error: Type 'Foo' has [Inject] tag on private property 'Bar'. [Inject] can only work on public properties.

It should probably handle [Inject] public Widget Bar { get; private set; } too, as that might happen when refactoring into Strange.

Problems polling cross-context events multiple times

I have a cross-context event PerformOperation, which takes as a parameter some operation object.

The command that eventually handles the event will make a callback to say if the operation was successful or not.

A client command raises this event with one parameter, and listens for the callbacks. If the operation fails, the callstack looks like this:

ClientCommand.OnOperationFailure()
...
EventDispatcher.Dispatch(OperationStatus.OperationFailure)
PerformOperationCommand.Execute()
...
EventDispatcher.Dispatch(Commands.PerformOperation, data)
CrossContextBridge.Trigger(Commands.PerformOperation, data)
EventDispatcher.Dispatch(Commands.PerformOperation, data)
ClientCommand.Execute()
...

In ClientCommand.OnOperationFailure(), the command then attempts to perform the operation again, with fallback data. However, CrossContextBridge already has PerformOperation down as an eventInProgress, so ignores subsequent calls.

This doesn't look like a bug so much as a false-positive in code that looks like it's meant to catch infinite loops.

So is there a better way to do this thing? Something more canonical? Or have I found an edge case that Strange should be able to handle, but currently isn't?

Constructor injection with ToSingleton returns NullPointerException

As reported by Vania:

Given this ClassA:

    using System;
    public class ClassA
    {
            public ClassB i;
            public ClassA (ClassB injected)
            {
                    i = injected;
            }
    }

And this ClassB:

    using System;
    public class ClassB
    {
            public ClassB ()
            {
            }
    }

The following code throws NPE.

injectionBinder.Bind<ClassB>().To<ClassB>();
injectionBinder.Bind<ClassA>().To<ClassA>().ToSingleton();
injectionBinder.GetInstance<ClassA>();

Request: commandBinder.Execute<MyCommand>();

1- PROBLEM

I would like to call a command (with injections inside) directly. An example I believe is architecturally sound is for a Command to arbitrarily call another Command directly.

My first attempt fails (because the injections inside);
new LoadButtonClickCommand().Execute();

2- SAMPLE SOLUTION
Per twitter @strangeioc offered this. It fails for the reasons given. A similar alternative would be acceptable for my needs. Something more terse would be better.

//LINE 160 BELOW
injectionBinder.Bind().To (typeof (LoadButtonClickCommand));

//LINE 162 BELOW
ICommand command = injectionBinder.GetInstance() as ICommand;

command.data = null;
command.Execute();
injectionBinder.Unbind();

// COMPILER ERROR ON LINE 162
// InjectionException: Attempt to Instantiate a null binding.
// target: com.rmc.projects.strangeioc_template.mvc.controller.commands.LoadButtonClickCommand
// type: com.rmc.projects.strangeioc_template.IService
// name:

3- MY PROPOSAL
With only my beginner's view of Strange, I recommend;

commandBinder.Execute< LoadButtonClickCommand >();

And this would not interfere-with/require-that any of that commands other existing bindings (e.g. signal-to-command binding)

Need some explanation for createFromValue exceptions

Hi!
I'm talks about InjectorFactory.cs:127. There are so many exceptions on call Activator.CreateInstance() and empty catch completely hides it. And we deal with obscure Null ref exception some time later.
Please consider exposing exception message of Activator.CreateInstance().

Unity compile errors in download 10ec34ef5d, Unity 4.2, OSX

Removing Assets/StrangeIoC/scripts/strange/extensions/entity because the asset does not exist // I guess me killing the last file in the folder stopped it existing?

Assets/StrangeIoC/scripts/strange/extensions/dispatcher/eventdispatcher/impl/EventBinding.cs(39,22): error CS0535: 
    `strange.extensions.dispatcher.eventdispatcher.impl.EventBinding' does not implement interface member 
    `strange.extensions.dispatcher.eventdispatcher.api.IEventBinding.typeForCallback(
        strange.extensions.dispatcher.eventdispatcher.api.EventCallback)'

Assets/StrangeIoC/scripts/strange/extensions/dispatcher/eventdispatcher/impl/EventBinding.cs(39,22): error CS0738: 
    `strange.extensions.dispatcher.eventdispatcher.impl.EventBinding' does not implement interface member 
    `strange.extensions.dispatcher.eventdispatcher.api.IEventBinding.To(
        strange.extensions.dispatcher.eventdispatcher.api.EventCallback)' 
    and the best implementing candidate 
    `strange.extensions.dispatcher.eventdispatcher.impl.EventBinding.typeForCallback( 
        strange.extensions.dispatcher.eventdispatcher.api.EmptyCallback)' 
        return type `strange.extensions.dispatcher.eventdispatcher.api.EventCallbackType' 
    does not match interface member return type `strange.extensions.dispatcher.eventdispatcher.api.IEventBinding'

These two are more serious. And a bit odd because I wasn't getting them with the previous download, c8805fd, and those files haven't changed since then.

[feature request] consistent coding standard

In MVCSContext.cs, among others, there are some functions in UpperCamelCase and some in lowerCamelCase. Both Unity3D and C# tend to have UpperCamelCase functions, but either choice is fine as long as Strange is consistent.

Exception on CrossContext.Start()

Steps to reproduce:

  1. Create empty project using CrossContext:
    class Program
        {
            static void Main(string[] args)
            {
                var testView = new object();
                var testContext = new CrossContext(testView, true);
                testContext.Start();
            }
        }
  1. Get an exception at Start():
    strange.extensions.injector.impl.InjectionException was unhandled
    Message=InjectionBinder has no binding for:
    key: strange.extensions.dispatcher.eventdispatcher.api.IEventDispatcher
    name: CONTEXT_DISPATCHER
    Source=Assembly-CSharp
    StackTrace:
    at strange.extensions.injector.impl.InjectionBinder.GetInstance(Type key, Object name) at c:\Users\Silentor\Documents\Visual Studio 2012\Projects\Test1\Test1\strangeioc-dev\Assets\scripts\strange\extensions\injector\impl\InjectionBinder.cs:line 58
    at strange.extensions.injector.impl.InjectionBinder.GetInstance[T](Object name) at c:\Users\Silentor\Documents\Visual Studio 2012\Projects\Test1\Test1\strangeioc-dev\Assets\scripts\strange\extensions\injector\impl\InjectionBinder.cs:line 74
    at strange.extensions.context.impl.CrossContext.instantiateCoreComponents() at c:\Users\Silentor\Documents\Visual Studio 2012\Projects\Test1\Test1\strangeioc-dev\Assets\scripts\strange\extensions\context\impl\CrossContext.cs:line 98
    at strange.extensions.context.impl.Context.Start() at c:\Users\Silentor\Documents\Visual Studio 2012\Projects\Test1\Test1\strangeioc-dev\Assets\scripts\strange\extensions\context\impl\Context.cs:line 92
    ...

Possible workaround - inherit CrossContext, override addCoreComponents() and bind context dispatcher manually:

protected override void addCoreComponents()
        {
            injectionBinder.Bind<IEventDispatcher>().To<EventDispatcher>().ToSingleton().ToName(ContextKeys.CONTEXT_DISPATCHER);
            base.addCoreComponents();
        }

Best practice for switching context.mapBindings() based on parent's model?

I need to switch my game to headless mode on a command line flag. Sounds like a model of command line flags with associated command to populate it!

Subcontexts will use this model to change commands and injections, yet an [Inject] public CommandLineModel Args { get; set; } in the MVCSContext-derived context doesn't get injected, at least not by mapBindings().

I can get it by asking the injector directly var args = injectorBinder.GetInstance<CommandLineModel>() as CommandLineModel; at the top of mapBindings(), but this doesn't seem like a very Strange way of doing it.

Is there a better way of going about this?

(Also, why does IInjectionBinder.GetInstance() return object, not T?)

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.