Initial Commit

This commit is contained in:
2026-03-16 14:38:46 +02:00
commit b8f7327a21
2327 changed files with 253610 additions and 0 deletions
@@ -0,0 +1,19 @@
using System;
namespace Zenject
{
public class ActionInstaller : Installer<ActionInstaller>
{
readonly Action<DiContainer> _installMethod;
public ActionInstaller(Action<DiContainer> installMethod)
{
_installMethod = installMethod;
}
public override void InstallBindings()
{
_installMethod(Container);
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e182a0b67fa936e40bebc0dc2f28743a
timeCreated: 1476911606
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,438 @@
using System.Linq;
using ModestTree;
using UnityEngine;
#pragma warning disable 219
namespace Zenject
{
public class CheatSheet : Installer<CheatSheet>
{
public override void InstallBindings()
{
// Create a new instance of Foo for every class that asks for it
Container.Bind<Foo>().AsTransient();
// Create a new instance of Foo for every class that asks for an IFoo
Container.Bind<IFoo>().To<Foo>().AsTransient();
// Non generic version of the above
Container.Bind(typeof(IFoo)).To(typeof(Foo)).AsTransient();
///////////// AsSingle
// Create one definitive instance of Foo and re-use that for every class that asks for it
Container.Bind<Foo>().AsSingle();
// Create one definitive instance of Foo and re-use that for every class that asks for IFoo
Container.Bind<IFoo>().To<Foo>().AsSingle();
// Bind the same instance to multiple types
// In this example, the same instance of Foo will be used for all three types
// (we have to use the non-generic version of Bind when mapping to multiple types)
Container.Bind(typeof(Foo), typeof(IFoo), typeof(IFoo2)).To<Foo>().AsSingle();
///////////// BindInterfaces
// This will have the exact same effect as the above line
// Bind all interfaces that Foo implements and Foo itself to a new singleton of type Foo
Container.BindInterfacesAndSelfTo<Foo>().AsSingle();
// Bind only the interfaces that Foo implements to an instance of Foo
// This can be useful if you don't want any classes to directly reference the concrete
// derived type
Container.BindInterfacesTo<Foo>().AsSingle();
///////////// FromInstance
// Use the given instance everywhere that Foo is used
// Note that in this case there's no good reason to use FromInstance
Container.Bind<Foo>().FromInstance(new Foo());
// This is simply a shortcut for the above binding
// This can be a bit nicer since the type argument can be deduced from the parameter
Container.BindInstance(new Foo());
// Bind multiple instances at once
Container.BindInstances(new Foo(), new Bar());
///////////// Binding primitive types
// BindInstance is more commonly used with primitive types
// Use the number 10 every time an int is requested
Container.Bind<int>().FromInstance(10);
Container.Bind<bool>().FromInstance(false);
// Or equivalently:
Container.BindInstance(10);
Container.BindInstance(false);
// You'd never really want to do the above though - you should almost always use a When condition for primitive values
Container.BindInstance(10).WhenInjectedInto<Foo>();
///////////// FromMethod
// Create instance of Foo when requested, using the given method
// Note that for more complex construction scenarios, you might consider using a factory
// instead with FromFactory
Container.Bind<Foo>().FromMethod(GetFoo);
// Randomly return one of several different implementations of IFoo
// We use Instantiate here instead of just new so that Foo1 gets its members injected
Container.Bind<IFoo>().FromMethod(GetRandomFoo);
// You an also use an anonymouse delegate directly
Container.Bind<Foo>().FromMethod(ctx => new Foo());
// This is equivalent to AsTransient
Container.Bind<Foo>().FromMethod(ctx => ctx.Container.Instantiate<Foo>());
InstallMore();
}
Foo GetFoo(InjectContext ctx)
{
return new Foo();
}
IFoo GetRandomFoo(InjectContext ctx)
{
switch (Random.Range(0, 3))
{
case 0:
{
return ctx.Container.Instantiate<Foo1>();
}
case 1:
{
return ctx.Container.Instantiate<Foo2>();
}
}
return ctx.Container.Instantiate<Foo3>();
}
void InstallMore()
{
///////////// FromResolveGetter
// Bind to a property on another dependency
// This can be helpful to reduce coupling between classes
Container.Bind<Foo>().AsSingle();
Container.Bind<Bar>().FromResolveGetter<Foo>(foo => foo.GetBar());
// Another example using values
Container.Bind<string>().FromResolveGetter<Foo>(foo => foo.GetTitle());
///////////// FromNewComponentOnNewGameObject
// Create a new game object at the root of the scene and add the Foo MonoBehaviour to it
Container.Bind<Foo>().FromNewComponentOnNewGameObject().AsSingle();
// You can also specify the game object name to use using WithGameObjectName
Container.Bind<Foo>().FromNewComponentOnNewGameObject().WithGameObjectName("Foo1").AsSingle();
// Bind to an interface instead
Container.Bind<IFoo>().To<Foo>().FromNewComponentOnNewGameObject().AsSingle();
///////////// FromComponentInNewPrefab (singleton)
// Create a new game object at the root of the scene using the given prefab
// After zenject creates a new GameObject from the given prefab, it will
// search the prefab for a component of type 'Foo' and return that
GameObject prefab = null;
Container.Bind<Foo>().FromComponentInNewPrefab(prefab).AsSingle();
// Bind to interface instead
Container.Bind<IFoo>().To<Foo>().FromComponentInNewPrefab(prefab).AsSingle();
// You can also add multiple components
// Note here that only one instance of the given prefab will be
// created
// For this to work, there must be both a Foo MonoBehaviour and
// a Bar MonoBehaviour somewhere on the prefab
Container.Bind(typeof(Foo), typeof(Bar)).FromComponentInNewPrefab(prefab).AsSingle();
///////////// FromComponentInNewPrefab (Transient)
// Instantiate a new copy of 'prefab' every time an instance of Foo is
// requested by a constructor parameter, injected field, etc.
Container.Bind<Foo>().FromComponentInNewPrefab(prefab).AsTransient();
// Bind to interface instead
Container.Bind<IFoo>().To<Foo>().FromComponentInNewPrefab(prefab);
///////////// Identifiers
// Bind a globally accessible string with the name 'PlayerName'
// Note however that a better option might be to create a Settings object and bind
// that instead
Container.Bind<string>().WithId("PlayerName").FromInstance("name of the player");
// This is the equivalent of the line above, and is a bit more readable
Container.BindInstance("name of the player").WithId("PlayerName");
// We can also use IDs to bind multiple instances of the same type:
Container.BindInstance("foo").WithId("FooA");
Container.BindInstance("asdf").WithId("FooB");
InstallMore2();
}
// Then when we inject these dependencies we have to use the same ID:
public class Norf
{
[Inject(Id = "FooA")]
public string Foo;
}
public class Qux
{
[Inject(Id = "FooB")]
public string Foo;
}
public void InstallMore2()
{
///////////// AsCached
// In this example, we bind three instances of Foo, including one without an ID
// We have to use AsCached here because Foo is not a singleton, but we also
// do not want a new Foo created every time like AsTransient
// This will result in a maximum of 3 instances of Foo
Container.Bind<Foo>().AsCached();
Container.Bind<Foo>().WithId("FooA").AsCached();
Container.Bind<Foo>().WithId("FooA").AsCached();
InstallMore3();
}
// When an ID is unspecified in an [Inject] field, it will use the first
// instance
// Bindings without IDs can therefore be used as a default and we can
// specify IDs for specific versions of the same type
public class Norf2
{
[Inject]
public Foo Foo;
}
// Qux2._foo will be the same instance as Norf2._foo
// This is because we are using AsCached rather than AsTransient
public class Qux2
{
[Inject]
public Foo Foo;
[Inject(Id = "FooA")]
public Foo Foo2;
}
public void InstallMore3()
{
///////////// Conditions
// This will make Foo only visible to Bar
// If we add Foo to the constructor of any other class it won't find it
Container.Bind<Foo>().AsSingle().WhenInjectedInto<Bar>();
// Use different implementations of IFoo dependending on which
// class is being injected
Container.Bind<IFoo>().To<Foo1>().AsSingle().WhenInjectedInto<Bar>();
Container.Bind<IFoo>().To<Foo2>().AsSingle().WhenInjectedInto<Qux>();
// Use "Foo1" as the default implementation except when injecting into
// class Qux, in which case use Foo2
// This works because if there is a condition match, that takes precedence
Container.Bind<IFoo>().To<Foo1>().AsSingle();
Container.Bind<IFoo>().To<Foo2>().AsSingle().WhenInjectedInto<Qux>();
// Allow depending on Foo in only a few select classes
Container.Bind<Foo>().AsSingle().WhenInjectedInto(typeof(Bar), typeof(Qux), typeof(Baz));
// Supply "my game" for any strings that are injected into the Gui class with the identifier "Title"
Container.BindInstance("my game").WithId("Title").WhenInjectedInto<Gui>();
// Supply 5 for all ints that are injected into the Gui class
Container.BindInstance(5).WhenInjectedInto<Gui>();
// Supply 5 for all ints that are injected into a parameter or field
// inside type Gui that is named 'width'
// Note that this is usually not a good idea since the name of a field can change
// easily and break the binding but shown here as an example of a more complex
// condition
Container.BindInstance(5.0f).When(ctx =>
ctx.ObjectType == typeof(Gui) && ctx.MemberName == "width");
// Create a new 'Foo' for every class that is created as part of the
// construction of the 'Bar' class
// So if Bar has a constructor parameter of type Qux, and Qux has
// a constructor parameter of type IFoo, a new Foo will be created
// for that case
Container.Bind<IFoo>().To<Foo>().AsTransient().When(
ctx => ctx.AllObjectTypes.Contains(typeof(Bar)));
///////////// Complex conditions example
var foo1 = new Foo();
var foo2 = new Foo();
Container.Bind<Bar>().WithId("Bar1").AsCached();
Container.Bind<Bar>().WithId("Bar2").AsCached();
// Here we use the 'ParentContexts' property of inject context to sync multiple corresponding identifiers
Container.BindInstance(foo1).When(c => c.ParentContexts.Where(x => x.MemberType == typeof(Bar) && Equals(x.Identifier, "Bar1")).Any());
Container.BindInstance(foo2).When(c => c.ParentContexts.Where(x => x.MemberType == typeof(Bar) && Equals(x.Identifier, "Bar2")).Any());
// This results in:
Assert.That(Container.ResolveId<Bar>("Bar1").Foo == foo1);
Assert.That(Container.ResolveId<Bar>("Bar2").Foo == foo2);
///////////// FromResolve
// FromResolve does another lookup on the container
// This will result in IBar, IFoo, and Foo, all being bound to the same instance of
// Foo which is assume to exist somewhere on the given prefab
GameObject fooPrefab = null;
Container.Bind<Foo>().FromComponentInNewPrefab(fooPrefab).AsSingle();
Container.Bind<IBar>().To<Foo>().FromResolve();
Container.Bind<IFoo>().To<IBar>().FromResolve();
// This will result in the same behaviour as the above
Container.Bind(typeof(Foo), typeof(IBar), typeof(IFoo)).To<Foo>().FromComponentInNewPrefab(fooPrefab).AsSingle();
InstallMore4();
}
public class FooInstaller : Installer<FooInstaller>
{
public FooInstaller(string foo)
{
}
public override void InstallBindings()
{
}
}
public class FooInstallerWithArgs : Installer<string, FooInstallerWithArgs>
{
public FooInstallerWithArgs(string foo)
{
}
public override void InstallBindings()
{
}
}
void InstallMore4()
{
///////////// Installing Other Installers
// Immediately call InstallBindings() on FooInstaller
FooInstaller.Install(Container);
// Before calling FooInstaller, configure a property of it
Container.BindInstance("foo").WhenInjectedInto<FooInstaller>();
FooInstaller.Install(Container);
// The arguments can also be added to the Installer<> generic arguments to make them
// strongly typed
FooInstallerWithArgs.Install(Container, "foo");
///////////// Manual Use of Container
// This will fill in any parameters marked as [Inject] and also call any [Inject] methods
var foo = new Foo();
Container.Inject(foo);
// Return an instance for IFoo, using the bindings that have been added previously
// Internally it is what is triggered when you fill in a constructor parameter of type IFoo
// Note: It will throw an exception if it cannot find a match
Container.Resolve<IFoo>();
// Same as the above except returns null when it can't find the given type
Container.TryResolve<IFoo>();
// Return a list of 2 instances of type Foo
// Note that in this case simply calling Resolve<IFoo> will trigger an exception
Container.BindInstance(new Foo());
Container.BindInstance(new Foo());
var foos = Container.ResolveAll<IFoo>();
// Create a new instance of Foo and inject on any of its members
// And fill in any constructor parameters Foo might have
Container.Instantiate<Foo>();
GameObject prefab1 = null;
GameObject prefab2 = null;
// Instantiate a new prefab and have any injectables filled in on the prefab
GameObject go = Container.InstantiatePrefab(prefab1);
// Instantiate a new prefab and return a specific monobehaviour
Foo foo2 = Container.InstantiatePrefabForComponent<Foo>(prefab2);
// Add a new component to an existing game object
Foo foo3 = Container.InstantiateComponent<Foo>(go);
}
public interface IFoo2
{
}
public interface IFoo
{
}
public interface IBar : IFoo
{
}
public class Foo : MonoBehaviour, IFoo, IFoo2, IBar
{
public Bar GetBar()
{
return new Bar();
}
public string GetTitle()
{
return "title";
}
}
public class Foo1 : IFoo
{
}
public class Foo2 : IFoo
{
}
public class Foo3 : IFoo
{
}
public class Baz
{
}
public class Gui
{
}
public class Bar : IBar
{
public Foo Foo
{
get
{
return null;
}
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 1d2fc6db101e75248ab98ad463a99ffa
timeCreated: 1528895686
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,53 @@
#if !NOT_UNITY3D
using System;
using UnityEngine;
namespace Zenject
{
public class DefaultGameObjectParentInstaller : Installer<string, DefaultGameObjectParentInstaller>
{
readonly string _name;
public DefaultGameObjectParentInstaller(string name)
{
_name = name;
}
public override void InstallBindings()
{
#if !ZEN_TESTS_OUTSIDE_UNITY
var defaultParent = new GameObject(_name);
defaultParent.transform.SetParent(
Container.InheritedDefaultParent, false);
Container.DefaultParent = defaultParent.transform;
Container.Bind<IDisposable>()
.To<DefaultParentObjectDestroyer>().AsCached().WithArguments(defaultParent);
// Always destroy the default parent last so that the non-monobehaviours get a chance
// to clean it up if they want to first
Container.BindDisposableExecutionOrder<DefaultParentObjectDestroyer>(int.MinValue);
#endif
}
class DefaultParentObjectDestroyer : IDisposable
{
readonly GameObject _gameObject;
public DefaultParentObjectDestroyer(GameObject gameObject)
{
_gameObject = gameObject;
}
public void Dispose()
{
GameObject.Destroy(_gameObject);
}
}
}
}
#endif
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: dd79d0a4f0b28314cbd6701ff5ab9062
timeCreated: 1538629352
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using ModestTree;
namespace Zenject
{
[NoReflectionBaking]
public class DisposeBlock : IDisposable
{
static readonly StaticMemoryPool<DisposeBlock> _pool =
new StaticMemoryPool<DisposeBlock>(OnSpawned, OnDespawned);
List<IDisposable> _disposables;
List<SpawnedObjectPoolPair> _objectPoolPairs;
static void OnSpawned(DisposeBlock that)
{
Assert.IsNull(that._disposables);
Assert.IsNull(that._objectPoolPairs);
}
static void OnDespawned(DisposeBlock that)
{
if (that._disposables != null)
{
// Dispose in reverse order since usually that makes the most sense
for (int i = that._disposables.Count - 1; i >= 0; i--)
{
that._disposables[i].Dispose();
}
ListPool<IDisposable>.Instance.Despawn(that._disposables);
that._disposables = null;
}
if (that._objectPoolPairs != null)
{
// Dispose in reverse order since usually that makes the most sense
for (int i = that._objectPoolPairs.Count - 1; i >= 0; i--)
{
var pair = that._objectPoolPairs[i];
pair.Pool.Despawn(pair.Object);
}
ListPool<SpawnedObjectPoolPair>.Instance.Despawn(that._objectPoolPairs);
that._objectPoolPairs = null;
}
}
void LazyInitializeDisposableList()
{
if (_disposables == null)
{
_disposables = ListPool<IDisposable>.Instance.Spawn();
}
}
public void AddRange<T>(IList<T> disposables)
where T : IDisposable
{
LazyInitializeDisposableList();
for (int i = 0; i < disposables.Count; i++)
{
_disposables.Add(disposables[i]);
}
}
public void Add(IDisposable disposable)
{
LazyInitializeDisposableList();
Assert.That(!_disposables.Contains(disposable));
_disposables.Add(disposable);
}
public void Remove(IDisposable disposable)
{
Assert.IsNotNull(_disposables);
_disposables.RemoveWithConfirm(disposable);
}
void StoreSpawnedObject<T>(T obj, IDespawnableMemoryPool<T> pool)
{
if (typeof(T).DerivesFrom<IDisposable>())
{
Add((IDisposable)obj);
}
else
{
// This allocation is ok because it's a struct
var pair = new SpawnedObjectPoolPair
{
Pool = pool,
Object = obj
};
if (_objectPoolPairs == null)
{
_objectPoolPairs = ListPool<SpawnedObjectPoolPair>.Instance.Spawn();
}
_objectPoolPairs.Add(pair);
}
}
public T Spawn<T>(IMemoryPool<T> pool)
{
var obj = pool.Spawn();
StoreSpawnedObject(obj, pool);
return obj;
}
public TValue Spawn<TValue, TParam1>(IMemoryPool<TParam1, TValue> pool, TParam1 p1)
{
var obj = pool.Spawn(p1);
StoreSpawnedObject(obj, pool);
return obj;
}
public TValue Spawn<TValue, TParam1, TParam2>(IMemoryPool<TParam1, TParam2, TValue> pool, TParam1 p1, TParam2 p2)
{
var obj = pool.Spawn(p1, p2);
StoreSpawnedObject(obj, pool);
return obj;
}
public TValue Spawn<TValue, TParam1, TParam2, TParam3>(IMemoryPool<TParam1, TParam2, TParam3, TValue> pool, TParam1 p1, TParam2 p2, TParam3 p3)
{
var obj = pool.Spawn(p1, p2, p3);
StoreSpawnedObject(obj, pool);
return obj;
}
public TValue Spawn<TValue, TParam1, TParam2, TParam3, TParam4>(IMemoryPool<TParam1, TParam2, TParam3, TParam4, TValue> pool, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4)
{
var obj = pool.Spawn(p1, p2, p3, p4);
StoreSpawnedObject(obj, pool);
return obj;
}
public TValue Spawn<TValue, TParam1, TParam2, TParam3, TParam4, TParam5>(IMemoryPool<TParam1, TParam2, TParam3, TParam4, TParam5, TValue> pool, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4, TParam5 p5)
{
var obj = pool.Spawn(p1, p2, p3, p4, p5);
StoreSpawnedObject(obj, pool);
return obj;
}
public TValue Spawn<TValue, TParam1, TParam2, TParam3, TParam4, TParam5, TParam6>(IMemoryPool<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TValue> pool, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4, TParam5 p5, TParam6 p6)
{
var obj = pool.Spawn(p1, p2, p3, p4, p5, p6);
StoreSpawnedObject(obj, pool);
return obj;
}
public TValue Spawn<TValue, TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TParam7>(IMemoryPool<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6, TParam7, TValue> pool, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4, TParam5 p5, TParam6 p6, TParam7 p7)
{
var obj = pool.Spawn(p1, p2, p3, p4, p5, p6, p7);
StoreSpawnedObject(obj, pool);
return obj;
}
public List<T> SpawnList<T>(IEnumerable<T> elements)
{
var list = SpawnList<T>();
list.AddRange(elements);
return list;
}
public List<T> SpawnList<T>()
{
return Spawn(ListPool<T>.Instance);
}
public static DisposeBlock Spawn()
{
return _pool.Spawn();
}
public void Dispose()
{
_pool.Despawn(this);
}
struct SpawnedObjectPoolPair
{
public IMemoryPool Pool;
public object Object;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 031fb76cf466ade4baf3269c39c146bd
timeCreated: 1519832826
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
namespace Zenject
{
public class ExecutionOrderInstaller : Installer<List<Type>, ExecutionOrderInstaller>
{
List<Type> _typeOrder;
public ExecutionOrderInstaller(List<Type> typeOrder)
{
_typeOrder = typeOrder;
}
public override void InstallBindings()
{
// All tickables without explicit priorities assigned are given order of zero,
// so put all of these before that (ie. negative)
int order = -1 * _typeOrder.Count;
foreach (var type in _typeOrder)
{
Container.BindExecutionOrder(type, order);
order++;
}
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: cad41a65c3c0b0f46a659557b2d716e0
timeCreated: 1461708053
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,210 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using ModestTree;
#if UNITY_EDITOR
using UnityEngine.Profiling;
using System.Threading;
#endif
namespace Zenject
{
[NoReflectionBaking]
public class ProfileBlock : IDisposable
{
#if UNITY_EDITOR
static int _blockCount;
static ProfileBlock _instance = new ProfileBlock();
static Dictionary<int, string> _nameCache = new Dictionary<int, string>();
ProfileBlock()
{
}
public static Thread UnityMainThread
{
get; set;
}
public static Regex ProfilePattern
{
get;
set;
}
static int GetHashCode(object p1, object p2)
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 29 + p1.GetHashCode();
hash = hash * 29 + p2.GetHashCode();
return hash;
}
}
static int GetHashCode(object p1, object p2, object p3)
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = hash * 29 + p1.GetHashCode();
hash = hash * 29 + p2.GetHashCode();
hash = hash * 29 + p3.GetHashCode();
return hash;
}
}
public static ProfileBlock Start(string sampleNameFormat, object obj1, object obj2)
{
#if ZEN_TESTS_OUTSIDE_UNITY
return null;
#else
if (UnityMainThread == null
|| !UnityMainThread.Equals(Thread.CurrentThread))
{
return null;
}
if (!Profiler.enabled)
{
return null;
}
// We need to ensure that we do not have per-frame allocations in ProfileBlock
// to avoid infecting the test too much, so use a cache of formatted strings given
// the input values
// This only works if the input values do not change per frame
var hash = GetHashCode(sampleNameFormat, obj1, obj2);
string formatString;
if (!_nameCache.TryGetValue(hash, out formatString))
{
formatString = string.Format(sampleNameFormat, obj1, obj2);
_nameCache.Add(hash, formatString);
}
return StartInternal(formatString);
#endif
}
public static ProfileBlock Start(string sampleNameFormat, object obj)
{
#if ZEN_TESTS_OUTSIDE_UNITY
return null;
#else
if (UnityMainThread == null
|| !UnityMainThread.Equals(Thread.CurrentThread))
{
return null;
}
if (!Profiler.enabled)
{
return null;
}
// We need to ensure that we do not have per-frame allocations in ProfileBlock
// to avoid infecting the test too much, so use a cache of formatted strings given
// the input values
// This only works if the input values do not change per frame
var hash = GetHashCode(sampleNameFormat, obj);
string formatString;
if (!_nameCache.TryGetValue(hash, out formatString))
{
formatString = string.Format(sampleNameFormat, obj);
_nameCache.Add(hash, formatString);
}
return StartInternal(formatString);
#endif
}
public static ProfileBlock Start(string sampleName)
{
#if ZEN_TESTS_OUTSIDE_UNITY
return null;
#else
if (UnityMainThread == null
|| !UnityMainThread.Equals(Thread.CurrentThread))
{
return null;
}
if (!Profiler.enabled)
{
return null;
}
return StartInternal(sampleName);
#endif
}
static ProfileBlock StartInternal(string sampleName)
{
Assert.That(Profiler.enabled);
if (ProfilePattern == null || ProfilePattern.Match(sampleName).Success)
{
Profiler.BeginSample(sampleName);
_blockCount++;
return _instance;
}
return null;
}
public void Dispose()
{
_blockCount--;
Assert.That(_blockCount >= 0);
Profiler.EndSample();
}
#else
ProfileBlock(string sampleName, bool rootBlock)
{
}
ProfileBlock(string sampleName)
: this(sampleName, false)
{
}
public static Regex ProfilePattern
{
get;
set;
}
public static ProfileBlock Start()
{
return null;
}
public static ProfileBlock Start(string sampleNameFormat, object obj1, object obj2)
{
return null;
}
// Remove the call completely for builds
public static ProfileBlock Start(string sampleNameFormat, object obj)
{
return null;
}
// Remove the call completely for builds
public static ProfileBlock Start(string sampleName)
{
return null;
}
public void Dispose()
{
}
#endif
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 952433523e6a6e445adc4ac7e2086e7d
timeCreated: 1485104137
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,168 @@
#if ZEN_INTERNAL_PROFILING
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ModestTree;
namespace Zenject
{
// Similar to ProfileBlock except used for measuring speed of zenject specifically
// And does not use unity's profiler
public static class ProfileTimers
{
static Dictionary<string, TimerInfo> _timers = new Dictionary<string, TimerInfo>();
public static void ResetAll()
{
foreach (var timer in _timers.Values)
{
timer.Reset();
}
}
public static string FormatResults()
{
var result = new StringBuilder();
// Uncomment if you only want to see zenject related info
//var timers = _timers.Where(x => x.Key != "User Code");
var timers = _timers;
var total = timers.Select(x => x.Value.TotalMilliseconds).Sum();
result.Append("Total time tracked: {0:0.00} ms. Details:".Fmt(total));
foreach (var pair in timers.OrderByDescending(x => x.Value.TotalMilliseconds))
{
var time = pair.Value.TotalMilliseconds;
var percent = 100.0 * (time / total);
var name = pair.Key;
result.Append("\n {0:00.0}% ({1:00000}x) ({2:0000} ms) {3}".Fmt(percent, pair.Value.CallCount, time, name));
}
return result.ToString();
}
public static double GetTimerElapsedMilliseconds(string name)
{
return _timers[name].TotalMilliseconds;
}
public static IDisposable CreateTimedBlock(string name)
{
TimerInfo timer;
if (!_timers.TryGetValue(name, out timer))
{
timer = new TimerInfo();
_timers.Add(name, timer);
}
timer.CallCount++;
if (timer.IsRunning)
{
return null;
}
return TimedBlock.Pool.Spawn(timer);
}
class TimedBlock : IDisposable
{
public static StaticMemoryPool<TimerInfo, TimedBlock> Pool =
new StaticMemoryPool<TimerInfo, TimedBlock>(OnSpawned, OnDespawned);
readonly List<TimerInfo> _pausedTimers = new List<TimerInfo>();
TimerInfo _exclusiveTimer;
static void OnSpawned(
TimerInfo exclusiveTimer, TimedBlock instance)
{
Assert.That(instance._pausedTimers.Count == 0);
instance._exclusiveTimer = exclusiveTimer;
foreach (var timer in _timers.Values)
{
if (exclusiveTimer == timer)
{
Assert.That(!timer.IsRunning);
timer.Resume();
}
else if (timer.IsRunning)
{
timer.Pause();
instance._pausedTimers.Add(timer);
}
}
}
static void OnDespawned(TimedBlock instance)
{
Assert.That(instance._exclusiveTimer.IsRunning);
instance._exclusiveTimer.Pause();
foreach (var timer in instance._pausedTimers)
{
Assert.That(!timer.IsRunning);
timer.Resume();
}
instance._pausedTimers.Clear();
}
public void Dispose()
{
Pool.Despawn(this);
}
}
public class TimerInfo
{
readonly Stopwatch _timer;
public TimerInfo()
{
_timer = new Stopwatch();
}
public int CallCount
{
get; set;
}
public double TotalMilliseconds
{
get { return _timer.Elapsed.TotalMilliseconds; }
}
public bool IsRunning
{
get { return _timer.IsRunning; }
}
public void Reset()
{
_timer.Reset();
}
public void Resume()
{
_timer.Start();
}
public void Pause()
{
_timer.Stop();
}
}
}
}
#endif
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 81cad1ee2d8c20942a68a4228e09ff1d
timeCreated: 1537522729
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,272 @@
//#define ZEN_DO_NOT_USE_COMPILED_EXPRESSIONS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using ModestTree;
#if !NOT_UNITY3D
using UnityEngine;
#endif
namespace Zenject.Internal
{
public static class ReflectionInfoTypeInfoConverter
{
public static InjectTypeInfo.InjectMethodInfo ConvertMethod(
ReflectionTypeInfo.InjectMethodInfo injectMethod)
{
var methodInfo = injectMethod.MethodInfo;
var action = TryCreateActionForMethod(methodInfo);
if (action == null)
{
action = (obj, args) => methodInfo.Invoke(obj, args);
}
return new InjectTypeInfo.InjectMethodInfo(
action,
injectMethod.Parameters.Select(x => x.InjectableInfo).ToArray(),
methodInfo.Name);
}
public static InjectTypeInfo.InjectConstructorInfo ConvertConstructor(
ReflectionTypeInfo.InjectConstructorInfo injectConstructor, Type type)
{
return new InjectTypeInfo.InjectConstructorInfo(
TryCreateFactoryMethod(type, injectConstructor),
injectConstructor.Parameters.Select(x => x.InjectableInfo).ToArray());
}
public static InjectTypeInfo.InjectMemberInfo ConvertField(
Type parentType, ReflectionTypeInfo.InjectFieldInfo injectField)
{
return new InjectTypeInfo.InjectMemberInfo(
GetSetter(parentType, injectField.FieldInfo), injectField.InjectableInfo);
}
public static InjectTypeInfo.InjectMemberInfo ConvertProperty(
Type parentType, ReflectionTypeInfo.InjectPropertyInfo injectProperty)
{
return new InjectTypeInfo.InjectMemberInfo(
GetSetter(parentType, injectProperty.PropertyInfo), injectProperty.InjectableInfo);
}
static ZenFactoryMethod TryCreateFactoryMethod(
Type type, ReflectionTypeInfo.InjectConstructorInfo reflectionInfo)
{
#if !NOT_UNITY3D
if (type.DerivesFromOrEqual<Component>())
{
return null;
}
#endif
if (type.IsAbstract())
{
Assert.That(reflectionInfo.Parameters.IsEmpty());
return null;
}
var constructor = reflectionInfo.ConstructorInfo;
var factoryMethod = TryCreateFactoryMethodCompiledLambdaExpression(type, constructor);
if (factoryMethod == null)
{
if (constructor == null)
{
// No choice in this case except to use the slow Activator.CreateInstance
// as far as I know
// This should be rare though and only seems to occur when instantiating
// structs on platforms that don't support lambda expressions
// Non-structs should always have a default constructor
factoryMethod = args =>
{
Assert.That(args.Length == 0);
return Activator.CreateInstance(type, new object[0]);
};
}
else
{
factoryMethod = constructor.Invoke;
}
}
return factoryMethod;
}
static ZenFactoryMethod TryCreateFactoryMethodCompiledLambdaExpression(
Type type, ConstructorInfo constructor)
{
#if NET_4_6 && !ENABLE_IL2CPP && !ZEN_DO_NOT_USE_COMPILED_EXPRESSIONS
if (type.ContainsGenericParameters)
{
return null;
}
ParameterExpression param = Expression.Parameter(typeof(object[]));
if (constructor == null)
{
return Expression.Lambda<ZenFactoryMethod>(
Expression.Convert(
Expression.New(type), typeof(object)), param).Compile();
}
ParameterInfo[] par = constructor.GetParameters();
Expression[] args = new Expression[par.Length];
for (int i = 0; i != par.Length; ++i)
{
args[i] = Expression.Convert(
Expression.ArrayIndex(
param, Expression.Constant(i)), par[i].ParameterType);
}
return Expression.Lambda<ZenFactoryMethod>(
Expression.Convert(
Expression.New(constructor, args), typeof(object)), param).Compile();
#else
return null;
#endif
}
static ZenInjectMethod TryCreateActionForMethod(MethodInfo methodInfo)
{
#if NET_4_6 && !ENABLE_IL2CPP && !ZEN_DO_NOT_USE_COMPILED_EXPRESSIONS
if (methodInfo.DeclaringType.ContainsGenericParameters)
{
return null;
}
ParameterInfo[] par = methodInfo.GetParameters();
if (par.Any(x => x.ParameterType.ContainsGenericParameters))
{
return null;
}
Expression[] args = new Expression[par.Length];
ParameterExpression argsParam = Expression.Parameter(typeof(object[]));
ParameterExpression instanceParam = Expression.Parameter(typeof(object));
for (int i = 0; i != par.Length; ++i)
{
args[i] = Expression.Convert(
Expression.ArrayIndex(
argsParam, Expression.Constant(i)), par[i].ParameterType);
}
return Expression.Lambda<ZenInjectMethod>(
Expression.Call(
Expression.Convert(instanceParam, methodInfo.DeclaringType), methodInfo, args),
instanceParam, argsParam).Compile();
#else
return null;
#endif
}
#if !(UNITY_WSA && ENABLE_DOTNET) || UNITY_EDITOR
static IEnumerable<FieldInfo> GetAllFields(Type t, BindingFlags flags)
{
if (t == null)
{
return Enumerable.Empty<FieldInfo>();
}
return t.GetFields(flags).Concat(GetAllFields(t.BaseType, flags)).Distinct();
}
static ZenMemberSetterMethod GetOnlyPropertySetter(
Type parentType,
string propertyName)
{
Assert.That(parentType != null);
Assert.That(!string.IsNullOrEmpty(propertyName));
var allFields = GetAllFields(
parentType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).ToList();
var writeableFields = allFields.Where(f => f.Name == string.Format("<" + propertyName + ">k__BackingField", propertyName)).ToList();
if (!writeableFields.Any())
{
throw new ZenjectException(string.Format(
"Can't find backing field for get only property {0} on {1}.\r\n{2}",
propertyName, parentType.FullName, string.Join(";", allFields.Select(f => f.Name).ToArray())));
}
return (injectable, value) => writeableFields.ForEach(f => f.SetValue(injectable, value));
}
#endif
static ZenMemberSetterMethod GetSetter(Type parentType, MemberInfo memInfo)
{
var setterMethod = TryGetSetterAsCompiledExpression(parentType, memInfo);
if (setterMethod != null)
{
return setterMethod;
}
var fieldInfo = memInfo as FieldInfo;
var propInfo = memInfo as PropertyInfo;
if (fieldInfo != null)
{
return ((injectable, value) => fieldInfo.SetValue(injectable, value));
}
Assert.IsNotNull(propInfo);
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return ((object injectable, object value) => propInfo.SetValue(injectable, value, null));
#else
if (propInfo.CanWrite)
{
return ((injectable, value) => propInfo.SetValue(injectable, value, null));
}
return GetOnlyPropertySetter(parentType, propInfo.Name);
#endif
}
static ZenMemberSetterMethod TryGetSetterAsCompiledExpression(Type parentType, MemberInfo memInfo)
{
#if NET_4_6 && !ENABLE_IL2CPP && !ZEN_DO_NOT_USE_COMPILED_EXPRESSIONS
if (parentType.ContainsGenericParameters)
{
return null;
}
var fieldInfo = memInfo as FieldInfo;
var propInfo = memInfo as PropertyInfo;
// It seems that for readonly fields, we have to use the slower approach below
// As discussed here: https://www.productiverage.com/trying-to-set-a-readonly-autoproperty-value-externally-plus-a-little-benchmarkdotnet
// We have to skip value types because those can only be set by reference using an lambda expression
if (!parentType.IsValueType() && (fieldInfo == null || !fieldInfo.IsInitOnly) && (propInfo == null || propInfo.CanWrite))
{
Type memberType = fieldInfo != null
? fieldInfo.FieldType : propInfo.PropertyType;
var typeParam = Expression.Parameter(typeof(object));
var valueParam = Expression.Parameter(typeof(object));
return Expression.Lambda<ZenMemberSetterMethod>(
Expression.Assign(
Expression.MakeMemberAccess(Expression.Convert(typeParam, parentType), memInfo),
Expression.Convert(valueParam, memberType)),
typeParam, valueParam).Compile();
}
#endif
return null;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: e36c348f078bc444fa1e5b22aca27bad
timeCreated: 1536916212
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Zenject.Internal
{
[NoReflectionBaking]
public class ReflectionTypeInfo
{
public readonly Type Type;
public readonly Type BaseType;
public readonly List<InjectPropertyInfo> InjectProperties;
public readonly List<InjectFieldInfo> InjectFields;
public readonly InjectConstructorInfo InjectConstructor;
public readonly List<InjectMethodInfo> InjectMethods;
public ReflectionTypeInfo(
Type type,
Type baseType,
InjectConstructorInfo injectConstructor,
List<InjectMethodInfo> injectMethods,
List<InjectFieldInfo> injectFields,
List<InjectPropertyInfo> injectProperties)
{
Type = type;
BaseType = baseType;
InjectFields = injectFields;
InjectConstructor = injectConstructor;
InjectMethods = injectMethods;
InjectProperties = injectProperties;
}
[NoReflectionBaking]
public class InjectFieldInfo
{
public readonly FieldInfo FieldInfo;
public readonly InjectableInfo InjectableInfo;
public InjectFieldInfo(
FieldInfo fieldInfo,
InjectableInfo injectableInfo)
{
InjectableInfo = injectableInfo;
FieldInfo = fieldInfo;
}
}
[NoReflectionBaking]
public class InjectParameterInfo
{
public readonly ParameterInfo ParameterInfo;
public readonly InjectableInfo InjectableInfo;
public InjectParameterInfo(
ParameterInfo parameterInfo,
InjectableInfo injectableInfo)
{
InjectableInfo = injectableInfo;
ParameterInfo = parameterInfo;
}
}
[NoReflectionBaking]
public class InjectPropertyInfo
{
public readonly PropertyInfo PropertyInfo;
public readonly InjectableInfo InjectableInfo;
public InjectPropertyInfo(
PropertyInfo propertyInfo,
InjectableInfo injectableInfo)
{
InjectableInfo = injectableInfo;
PropertyInfo = propertyInfo;
}
}
[NoReflectionBaking]
public class InjectMethodInfo
{
public readonly MethodInfo MethodInfo;
public readonly List<InjectParameterInfo> Parameters;
public InjectMethodInfo(
MethodInfo methodInfo,
List<InjectParameterInfo> parameters)
{
MethodInfo = methodInfo;
Parameters = parameters;
}
}
[NoReflectionBaking]
public class InjectConstructorInfo
{
public readonly ConstructorInfo ConstructorInfo;
public readonly List<InjectParameterInfo> Parameters;
public InjectConstructorInfo(
ConstructorInfo constructorInfo,
List<InjectParameterInfo> parameters)
{
ConstructorInfo = constructorInfo;
Parameters = parameters;
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 5490313f008f146458b6228165838735
timeCreated: 1536916212
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,166 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace ModestTree
{
public static class ReflectionUtil
{
public static Array CreateArray(Type elementType, List<object> instances)
{
var array = Array.CreateInstance(elementType, instances.Count);
for (int i = 0; i < instances.Count; i++)
{
var instance = instances[i];
if (instance != null)
{
Assert.That(instance.GetType().DerivesFromOrEqual(elementType),
"Wrong type when creating array, expected something assignable from '"+ elementType +"', but found '" + instance.GetType() + "'");
}
array.SetValue(instance, i);
}
return array;
}
public static IList CreateGenericList(Type elementType, List<object> instances)
{
var genericType = typeof(List<>).MakeGenericType(elementType);
var list = (IList)Activator.CreateInstance(genericType);
for (int i = 0; i < instances.Count; i++)
{
var instance = instances[i];
if (instance != null)
{
Assert.That(instance.GetType().DerivesFromOrEqual(elementType),
"Wrong type when creating generic list, expected something assignable from '"+ elementType +"', but found '" + instance.GetType() + "'");
}
list.Add(instance);
}
return list;
}
public static string ToDebugString(this MethodInfo method)
{
return "{0}.{1}".Fmt(method.DeclaringType.PrettyName(), method.Name);
}
public static string ToDebugString(this Action action)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return action.ToString();
#else
return action.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1>(this Action<TParam1> action)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return action.ToString();
#else
return action.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1, TParam2>(this Action<TParam1, TParam2> action)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return action.ToString();
#else
return action.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1, TParam2, TParam3>(this Action<TParam1, TParam2, TParam3> action)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return action.ToString();
#else
return action.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1, TParam2, TParam3, TParam4>(this Action<TParam1, TParam2, TParam3, TParam4> action)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return action.ToString();
#else
return action.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1, TParam2, TParam3, TParam4, TParam5>(this
#if NET_4_6
Action<TParam1, TParam2, TParam3, TParam4, TParam5> action)
#else
ModestTree.Util.Action<TParam1, TParam2, TParam3, TParam4, TParam5> action)
#endif
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return action.ToString();
#else
return action.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6>(this
#if NET_4_6
Action<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6> action)
#else
ModestTree.Util.Action<TParam1, TParam2, TParam3, TParam4, TParam5, TParam6> action)
#endif
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return action.ToString();
#else
return action.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1>(this Func<TParam1> func)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return func.ToString();
#else
return func.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1, TParam2>(this Func<TParam1, TParam2> func)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return func.ToString();
#else
return func.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1, TParam2, TParam3>(this Func<TParam1, TParam2, TParam3> func)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return func.ToString();
#else
return func.Method.ToDebugString();
#endif
}
public static string ToDebugString<TParam1, TParam2, TParam3, TParam4>(this Func<TParam1, TParam2, TParam3, TParam4> func)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return func.ToString();
#else
return func.Method.ToDebugString();
#endif
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 7c74b10dac7e87e4095f8e3157eb040d
timeCreated: 1520399530
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,249 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using ModestTree;
using Zenject.Internal;
namespace Zenject
{
public delegate InjectTypeInfo ZenTypeInfoGetter();
public enum ReflectionBakingCoverageModes
{
FallbackToDirectReflection,
NoCheckAssumeFullCoverage,
FallbackToDirectReflectionWithWarning
}
public static class TypeAnalyzer
{
static Dictionary<Type, InjectTypeInfo> _typeInfo = new Dictionary<Type, InjectTypeInfo>();
// We store this separately from InjectTypeInfo because this flag is needed for contract
// types whereas InjectTypeInfo is only needed for types that are instantiated, and
// we want to minimize the types that generate InjectTypeInfo for
static Dictionary<Type, bool> _allowDuringValidation = new Dictionary<Type, bool>();
// Use double underscores for generated methods since this is also what the C# compiler does
// for things like anonymous methods
public const string ReflectionBakingGetInjectInfoMethodName = "__zenCreateInjectTypeInfo";
public const string ReflectionBakingFactoryMethodName = "__zenCreate";
public const string ReflectionBakingInjectMethodPrefix = "__zenInjectMethod";
public const string ReflectionBakingFieldSetterPrefix = "__zenFieldSetter";
public const string ReflectionBakingPropertySetterPrefix = "__zenPropertySetter";
public static ReflectionBakingCoverageModes ReflectionBakingCoverageMode
{
get; set;
}
public static bool ShouldAllowDuringValidation<T>()
{
return ShouldAllowDuringValidation(typeof(T));
}
public static bool ShouldAllowDuringValidation(Type type)
{
bool shouldAllow;
if (!_allowDuringValidation.TryGetValue(type, out shouldAllow))
{
shouldAllow = ShouldAllowDuringValidationInternal(type);
_allowDuringValidation.Add(type, shouldAllow);
}
return shouldAllow;
}
static bool ShouldAllowDuringValidationInternal(Type type)
{
// During validation, do not instantiate or inject anything except for
// Installers, IValidatable's, or types marked with attribute ZenjectAllowDuringValidation
// You would typically use ZenjectAllowDuringValidation attribute for data that you
// inject into factories
if (type.DerivesFrom<IInstaller>() || type.DerivesFrom<IValidatable>())
{
return true;
}
#if !NOT_UNITY3D
if (type.DerivesFrom<Context>())
{
return true;
}
#endif
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
return type.GetTypeInfo().GetCustomAttribute<ZenjectAllowDuringValidationAttribute>() != null;
#else
return type.HasAttribute<ZenjectAllowDuringValidationAttribute>();
#endif
}
public static bool HasInfo<T>()
{
return HasInfo(typeof(T));
}
public static bool HasInfo(Type type)
{
return TryGetInfo(type) != null;
}
public static InjectTypeInfo GetInfo<T>()
{
return GetInfo(typeof(T));
}
public static InjectTypeInfo GetInfo(Type type)
{
var info = TryGetInfo(type);
Assert.IsNotNull(info, "Unable to get type info for type '{0}'", type);
return info;
}
public static InjectTypeInfo TryGetInfo<T>()
{
return TryGetInfo(typeof(T));
}
public static InjectTypeInfo TryGetInfo(Type type)
{
InjectTypeInfo info;
#if ZEN_MULTITHREADING
lock (_typeInfo)
#endif
{
if (_typeInfo.TryGetValue(type, out info))
{
return info;
}
}
#if UNITY_EDITOR
using (ProfileBlock.Start("Zenject Reflection"))
#endif
{
info = GetInfoInternal(type);
}
if (info != null)
{
Assert.IsEqual(info.Type, type);
Assert.IsNull(info.BaseTypeInfo);
var baseType = type.BaseType();
if (baseType != null && !ShouldSkipTypeAnalysis(baseType))
{
info.BaseTypeInfo = TryGetInfo(baseType);
}
}
#if ZEN_MULTITHREADING
lock (_typeInfo)
#endif
{
_typeInfo[type] = info;
}
return info;
}
static InjectTypeInfo GetInfoInternal(Type type)
{
if (ShouldSkipTypeAnalysis(type))
{
return null;
}
#if ZEN_INTERNAL_PROFILING
// Make sure that the static constructor logic doesn't inflate our profile measurements
using (ProfileTimers.CreateTimedBlock("User Code"))
{
RuntimeHelpers.RunClassConstructor(type.TypeHandle);
}
#endif
#if ZEN_INTERNAL_PROFILING
using (ProfileTimers.CreateTimedBlock("Type Analysis - Calling Baked Reflection Getter"))
#endif
{
var getInfoMethod = type.GetMethod(
ReflectionBakingGetInjectInfoMethodName,
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
if (getInfoMethod != null)
{
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
var infoGetter = (ZenTypeInfoGetter)getInfoMethod.CreateDelegate(
typeof(ZenTypeInfoGetter), null);
#else
var infoGetter = ((ZenTypeInfoGetter)Delegate.CreateDelegate(
typeof(ZenTypeInfoGetter), getInfoMethod));
#endif
return infoGetter();
}
}
if (ReflectionBakingCoverageMode == ReflectionBakingCoverageModes.NoCheckAssumeFullCoverage)
{
// If we are confident that the reflection baking supplies all the injection information,
// then we can avoid the costs of doing reflection on types that were not covered
// by the baking
return null;
}
#if !(UNITY_WSA && ENABLE_DOTNET) || UNITY_EDITOR
if (ReflectionBakingCoverageMode == ReflectionBakingCoverageModes.FallbackToDirectReflectionWithWarning)
{
Log.Warn("No reflection baking information found for type '{0}' - using more costly direct reflection instead", type);
}
#endif
#if ZEN_INTERNAL_PROFILING
using (ProfileTimers.CreateTimedBlock("Type Analysis - Direct Reflection"))
#endif
{
return CreateTypeInfoFromReflection(type);
}
}
public static bool ShouldSkipTypeAnalysis(Type type)
{
return type == null || type.IsEnum() || type.IsArray || type.IsInterface()
|| type.ContainsGenericParameters() || IsStaticType(type)
|| type == typeof(object);
}
static bool IsStaticType(Type type)
{
// Apparently this is unique to static classes
return type.IsAbstract() && type.IsSealed();
}
static InjectTypeInfo CreateTypeInfoFromReflection(Type type)
{
var reflectionInfo = ReflectionTypeAnalyzer.GetReflectionInfo(type);
var injectConstructor = ReflectionInfoTypeInfoConverter.ConvertConstructor(
reflectionInfo.InjectConstructor, type);
var injectMethods = reflectionInfo.InjectMethods.Select(
ReflectionInfoTypeInfoConverter.ConvertMethod).ToArray();
var memberInfos = reflectionInfo.InjectFields.Select(
x => ReflectionInfoTypeInfoConverter.ConvertField(type, x)).Concat(
reflectionInfo.InjectProperties.Select(
x => ReflectionInfoTypeInfoConverter.ConvertProperty(type, x))).ToArray();
return new InjectTypeInfo(
type, injectConstructor, injectMethods, memberInfos);
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7359cd850f5a96d47ad4606d14dac326
timeCreated: 1461708051
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,139 @@
#if !NOT_UNITY3D
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace ModestTree.Util
{
public static class UnityUtil
{
public static IEnumerable<Scene> AllScenes
{
get
{
for (int i = 0; i < SceneManager.sceneCount; i++)
{
yield return SceneManager.GetSceneAt(i);
}
}
}
public static IEnumerable<Scene> AllLoadedScenes
{
get { return AllScenes.Where(scene => scene.isLoaded); }
}
public static bool IsAltKeyDown
{
get { return Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt); }
}
public static bool IsControlKeyDown
{
get { return Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl); }
}
public static bool IsShiftKeyDown
{
get { return Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift); }
}
public static bool WasShiftKeyJustPressed
{
get { return Input.GetKeyDown(KeyCode.LeftShift) || Input.GetKeyDown(KeyCode.RightShift); }
}
public static bool WasAltKeyJustPressed
{
get { return Input.GetKeyDown(KeyCode.LeftAlt) || Input.GetKeyDown(KeyCode.RightAlt); }
}
public static int GetDepthLevel(Transform transform)
{
if (transform == null)
{
return 0;
}
return 1 + GetDepthLevel(transform.parent);
}
public static GameObject GetRootParentOrSelf(GameObject gameObject)
{
return GetParentsAndSelf(gameObject.transform).Select(x => x.gameObject).LastOrDefault();
}
public static IEnumerable<Transform> GetParents(Transform transform)
{
if (transform == null)
{
yield break;
}
foreach (var ancestor in GetParentsAndSelf(transform.parent))
{
yield return ancestor;
}
}
public static IEnumerable<Transform> GetParentsAndSelf(Transform transform)
{
if (transform == null)
{
yield break;
}
yield return transform;
foreach (var ancestor in GetParentsAndSelf(transform.parent))
{
yield return ancestor;
}
}
public static IEnumerable<Component> GetComponentsInChildrenTopDown(GameObject gameObject, bool includeInactive)
{
return gameObject.GetComponentsInChildren<Component>(includeInactive)
.OrderBy(x =>
x == null ? int.MinValue : GetDepthLevel(x.transform));
}
public static IEnumerable<Component> GetComponentsInChildrenBottomUp(GameObject gameObject, bool includeInactive)
{
return gameObject.GetComponentsInChildren<Component>(includeInactive)
.OrderByDescending(x =>
x == null ? int.MinValue : GetDepthLevel(x.transform));
}
public static IEnumerable<GameObject> GetDirectChildrenAndSelf(GameObject obj)
{
yield return obj;
foreach (Transform child in obj.transform)
{
yield return child.gameObject;
}
}
public static IEnumerable<GameObject> GetDirectChildren(GameObject obj)
{
foreach (Transform child in obj.transform)
{
yield return child.gameObject;
}
}
public static IEnumerable<GameObject> GetAllGameObjects()
{
return GameObject.FindObjectsOfType<Transform>().Select(x => x.gameObject);
}
public static List<GameObject> GetAllRootGameObjects()
{
return GetAllGameObjects().Where(x => x.transform.parent == null).ToList();
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 136cacfad8fe5404aad05dda29a777e4
timeCreated: 1461708048
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ModestTree;
namespace Zenject
{
public static class ValidationUtil
{
// This method can be used during validation for cases where we need to pass arguments
public static List<TypeValuePair> CreateDefaultArgs(params Type[] argTypes)
{
return argTypes.Select(x => new TypeValuePair(x, x.GetDefaultValue())).ToList();
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 018820e0bcd9a4049a305127c0cf1407
timeCreated: 1461708048
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,73 @@
using ModestTree;
using UnityEngine;
namespace Zenject
{
public class ZenAutoInjecter : MonoBehaviour
{
[SerializeField]
ContainerSources _containerSource = ContainerSources.SearchHierarchy;
bool _hasInjected;
public ContainerSources ContainerSource
{
get { return _containerSource; }
set { _containerSource = value; }
}
// Make sure they don't cause injection to happen twice
[Inject]
public void Construct()
{
if (!_hasInjected)
{
throw Assert.CreateException(
"ZenAutoInjecter was injected! Do not use ZenAutoInjecter for objects that are instantiated through zenject or which exist in the initial scene hierarchy");
}
}
public void Awake()
{
_hasInjected = true;
LookupContainer().InjectGameObject(gameObject);
}
DiContainer LookupContainer()
{
if (_containerSource == ContainerSources.ProjectContext)
{
return ProjectContext.Instance.Container;
}
if (_containerSource == ContainerSources.SceneContext)
{
return GetContainerForCurrentScene();
}
Assert.IsEqual(_containerSource, ContainerSources.SearchHierarchy);
var parentContext = transform.GetComponentInParent<Context>();
if (parentContext != null)
{
return parentContext.Container;
}
return GetContainerForCurrentScene();
}
DiContainer GetContainerForCurrentScene()
{
return ProjectContext.Instance.Container.Resolve<SceneContextRegistry>()
.GetContainerForScene(gameObject.scene);
}
public enum ContainerSources
{
SceneContext,
ProjectContext,
SearchHierarchy
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 717a02054ef2699498e6bd4234fd7995
timeCreated: 1510660712
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
namespace Zenject.Internal
{
public static class ZenPools
{
#if ZEN_INTERNAL_NO_POOLS
public static InjectContext SpawnInjectContext(DiContainer container, Type memberType)
{
return new InjectContext(container, memberType);
}
public static void DespawnInjectContext(InjectContext context)
{
}
public static List<T> SpawnList<T>()
{
return new List<T>();
}
public static void DespawnList<T>(List<T> list)
{
}
public static void DespawnArray<T>(T[] arr)
{
}
public static T[] SpawnArray<T>(int length)
{
return new T[length];
}
public static HashSet<T> SpawnHashSet<T>()
{
return new HashSet<T>();
}
public static Dictionary<TKey, TValue> SpawnDictionary<TKey, TValue>()
{
return new Dictionary<TKey, TValue>();
}
public static void DespawnDictionary<TKey, TValue>(Dictionary<TKey, TValue> dictionary)
{
}
public static void DespawnHashSet<T>(HashSet<T> set)
{
}
public static LookupId SpawnLookupId(IProvider provider, BindingId bindingId)
{
return new LookupId(provider, bindingId);
}
public static void DespawnLookupId(LookupId lookupId)
{
}
public static BindInfo SpawnBindInfo()
{
return new BindInfo();
}
public static void DespawnBindInfo(BindInfo bindInfo)
{
}
public static BindStatement SpawnStatement()
{
return new BindStatement();
}
public static void DespawnStatement(BindStatement statement)
{
}
#else
static readonly StaticMemoryPool<InjectContext> _contextPool = new StaticMemoryPool<InjectContext>();
static readonly StaticMemoryPool<LookupId> _lookupIdPool = new StaticMemoryPool<LookupId>();
static readonly StaticMemoryPool<BindInfo> _bindInfoPool = new StaticMemoryPool<BindInfo>();
static readonly StaticMemoryPool<BindStatement> _bindStatementPool = new StaticMemoryPool<BindStatement>();
public static HashSet<T> SpawnHashSet<T>()
{
return HashSetPool<T>.Instance.Spawn();
}
public static Dictionary<TKey, TValue> SpawnDictionary<TKey, TValue>()
{
return DictionaryPool<TKey, TValue>.Instance.Spawn();
}
public static BindStatement SpawnStatement()
{
return _bindStatementPool.Spawn();
}
public static void DespawnStatement(BindStatement statement)
{
statement.Reset();
_bindStatementPool.Despawn(statement);
}
public static BindInfo SpawnBindInfo()
{
return _bindInfoPool.Spawn();
}
public static void DespawnBindInfo(BindInfo bindInfo)
{
bindInfo.Reset();
_bindInfoPool.Despawn(bindInfo);
}
public static void DespawnDictionary<TKey, TValue>(Dictionary<TKey, TValue> dictionary)
{
DictionaryPool<TKey, TValue>.Instance.Despawn(dictionary);
}
public static void DespawnHashSet<T>(HashSet<T> set)
{
HashSetPool<T>.Instance.Despawn(set);
}
public static LookupId SpawnLookupId(IProvider provider, BindingId bindingId)
{
var lookupId = _lookupIdPool.Spawn();
lookupId.Provider = provider;
lookupId.BindingId = bindingId;
return lookupId;
}
public static void DespawnLookupId(LookupId lookupId)
{
lookupId.Reset();
_lookupIdPool.Despawn(lookupId);
}
public static List<T> SpawnList<T>()
{
return ListPool<T>.Instance.Spawn();
}
public static void DespawnList<T>(List<T> list)
{
ListPool<T>.Instance.Despawn(list);
}
public static void DespawnArray<T>(T[] arr)
{
ArrayPool<T>.GetPool(arr.Length).Despawn(arr);
}
public static T[] SpawnArray<T>(int length)
{
return ArrayPool<T>.GetPool(length).Spawn();
}
public static InjectContext SpawnInjectContext(DiContainer container, Type memberType)
{
var context = _contextPool.Spawn();
context.Container = container;
context.MemberType = memberType;
return context;
}
public static void DespawnInjectContext(InjectContext context)
{
context.Reset();
_contextPool.Despawn(context);
}
#endif
public static InjectContext SpawnInjectContext(
DiContainer container, InjectableInfo injectableInfo, InjectContext currentContext,
object targetInstance, Type targetType, object concreteIdentifier)
{
var context = SpawnInjectContext(container, injectableInfo.MemberType);
context.ObjectType = targetType;
context.ParentContext = currentContext;
context.ObjectInstance = targetInstance;
context.Identifier = injectableInfo.Identifier;
context.MemberName = injectableInfo.MemberName;
context.Optional = injectableInfo.Optional;
context.SourceType = injectableInfo.SourceType;
context.FallBackValue = injectableInfo.DefaultValue;
context.ConcreteIdentifier = concreteIdentifier;
return context;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 14ff296505fe79448b0c79ec09977477
timeCreated: 1535860932
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,261 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using ModestTree;
#if !NOT_UNITY3D
using UnityEngine;
#endif
namespace Zenject.Internal
{
public static class ReflectionTypeAnalyzer
{
static readonly HashSet<Type> _injectAttributeTypes;
static ReflectionTypeAnalyzer()
{
_injectAttributeTypes = new HashSet<Type>();
_injectAttributeTypes.Add(typeof(InjectAttributeBase));
}
public static void AddCustomInjectAttribute<T>()
where T : Attribute
{
AddCustomInjectAttribute(typeof(T));
}
public static void AddCustomInjectAttribute(Type type)
{
Assert.That(type.DerivesFrom<Attribute>());
_injectAttributeTypes.Add(type);
}
public static ReflectionTypeInfo GetReflectionInfo(Type type)
{
Assert.That(!type.IsEnum(), "Tried to analyze enum type '{0}'. This is not supported", type);
Assert.That(!type.IsArray, "Tried to analyze array type '{0}'. This is not supported", type);
var baseType = type.BaseType();
if (baseType == typeof(object))
{
baseType = null;
}
return new ReflectionTypeInfo(
type, baseType, GetConstructorInfo(type), GetMethodInfos(type),
GetFieldInfos(type), GetPropertyInfos(type));
}
static List<ReflectionTypeInfo.InjectPropertyInfo> GetPropertyInfos(Type type)
{
return type.DeclaredInstanceProperties()
.Where(x => _injectAttributeTypes.Any(a => x.HasAttribute(a)))
.Select(x => new ReflectionTypeInfo.InjectPropertyInfo(
x, GetInjectableInfoForMember(type, x))).ToList();
}
static List<ReflectionTypeInfo.InjectFieldInfo> GetFieldInfos(Type type)
{
return type.DeclaredInstanceFields()
.Where(x => _injectAttributeTypes.Any(a => x.HasAttribute(a)))
.Select(x => new ReflectionTypeInfo.InjectFieldInfo(
x, GetInjectableInfoForMember(type, x)))
.ToList();
}
static List<ReflectionTypeInfo.InjectMethodInfo> GetMethodInfos(Type type)
{
var injectMethodInfos = new List<ReflectionTypeInfo.InjectMethodInfo>();
// Note that unlike with fields and properties we use GetCustomAttributes
// This is so that we can ignore inherited attributes, which is necessary
// otherwise a base class method marked with [Inject] would cause all overridden
// derived methods to be added as well
var methodInfos = type.DeclaredInstanceMethods()
.Where(x => _injectAttributeTypes.Any(a => x.GetCustomAttributes(a, false).Any())).ToList();
for (int i = 0; i < methodInfos.Count; i++)
{
var methodInfo = methodInfos[i];
var injectAttr = methodInfo.AllAttributes<InjectAttributeBase>().SingleOrDefault();
if (injectAttr != null)
{
Assert.That(!injectAttr.Optional && injectAttr.Id == null && injectAttr.Source == InjectSources.Any,
"Parameters of InjectAttribute do not apply to constructors and methodInfos");
}
var injectParamInfos = methodInfo.GetParameters()
.Select(x => CreateInjectableInfoForParam(type, x)).ToList();
injectMethodInfos.Add(
new ReflectionTypeInfo.InjectMethodInfo(methodInfo, injectParamInfos));
}
return injectMethodInfos;
}
static ReflectionTypeInfo.InjectConstructorInfo GetConstructorInfo(Type type)
{
var args = new List<ReflectionTypeInfo.InjectParameterInfo>();
var constructor = TryGetInjectConstructor(type);
if (constructor != null)
{
args.AddRange(constructor.GetParameters().Select(
x => CreateInjectableInfoForParam(type, x)));
}
return new ReflectionTypeInfo.InjectConstructorInfo(constructor, args);
}
static ReflectionTypeInfo.InjectParameterInfo CreateInjectableInfoForParam(
Type parentType, ParameterInfo paramInfo)
{
var injectAttributes = paramInfo.AllAttributes<InjectAttributeBase>().ToList();
Assert.That(injectAttributes.Count <= 1,
"Found multiple 'Inject' attributes on type parameter '{0}' of type '{1}'. Parameter should only have one", paramInfo.Name, parentType);
var injectAttr = injectAttributes.SingleOrDefault();
object identifier = null;
bool isOptional = false;
InjectSources sourceType = InjectSources.Any;
if (injectAttr != null)
{
identifier = injectAttr.Id;
isOptional = injectAttr.Optional;
sourceType = injectAttr.Source;
}
bool isOptionalWithADefaultValue = (paramInfo.Attributes & ParameterAttributes.HasDefault) == ParameterAttributes.HasDefault;
return new ReflectionTypeInfo.InjectParameterInfo(
paramInfo,
new InjectableInfo(
isOptionalWithADefaultValue || isOptional,
identifier,
paramInfo.Name,
paramInfo.ParameterType,
isOptionalWithADefaultValue ? paramInfo.DefaultValue : null,
sourceType));
}
static InjectableInfo GetInjectableInfoForMember(Type parentType, MemberInfo memInfo)
{
var injectAttributes = memInfo.AllAttributes<InjectAttributeBase>().ToList();
Assert.That(injectAttributes.Count <= 1,
"Found multiple 'Inject' attributes on type field '{0}' of type '{1}'. Field should only container one Inject attribute", memInfo.Name, parentType);
var injectAttr = injectAttributes.SingleOrDefault();
object identifier = null;
bool isOptional = false;
InjectSources sourceType = InjectSources.Any;
if (injectAttr != null)
{
identifier = injectAttr.Id;
isOptional = injectAttr.Optional;
sourceType = injectAttr.Source;
}
Type memberType = memInfo is FieldInfo
? ((FieldInfo)memInfo).FieldType : ((PropertyInfo)memInfo).PropertyType;
return new InjectableInfo(
isOptional,
identifier,
memInfo.Name,
memberType,
null,
sourceType);
}
static ConstructorInfo TryGetInjectConstructor(Type type)
{
#if !NOT_UNITY3D
if (type.DerivesFromOrEqual<Component>())
{
return null;
}
#endif
if (type.IsAbstract())
{
return null;
}
var constructors = type.Constructors();
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
// WP8 generates a dummy constructor with signature (internal Classname(UIntPtr dummy))
// So just ignore that
constructors = constructors.Where(c => !IsWp8GeneratedConstructor(c)).ToArray();
#endif
if (constructors.IsEmpty())
{
return null;
}
if (constructors.HasMoreThan(1))
{
var explicitConstructor = (from c in constructors where _injectAttributeTypes.Any(a => c.HasAttribute(a)) select c).SingleOrDefault();
if (explicitConstructor != null)
{
return explicitConstructor;
}
// If there is only one public constructor then use that
// This makes decent sense but is also necessary on WSA sometimes since the WSA generated
// constructor can sometimes be private with zero parameters
var singlePublicConstructor = constructors.Where(x => x.IsPublic).OnlyOrDefault();
if (singlePublicConstructor != null)
{
return singlePublicConstructor;
}
// Choose the one with the least amount of arguments
// This might result in some non obvious errors like null reference exceptions
// but is probably the best trade-off since it allows zenject to be more compatible
// with libraries that don't depend on zenject at all
// Discussion here - https://github.com/svermeulen/Zenject/issues/416
return constructors.OrderBy(x => x.GetParameters().Count()).First();
}
return constructors[0];
}
#if UNITY_WSA && ENABLE_DOTNET && !UNITY_EDITOR
static bool IsWp8GeneratedConstructor(ConstructorInfo c)
{
ParameterInfo[] args = c.GetParameters();
if (args.Length == 1)
{
return args[0].ParameterType == typeof(UIntPtr)
&& (string.IsNullOrEmpty(args[0].Name) || args[0].Name == "dummy");
}
if (args.Length == 2)
{
return args[0].ParameterType == typeof(UIntPtr)
&& args[1].ParameterType == typeof(Int64*)
&& (string.IsNullOrEmpty(args[0].Name) || args[0].Name == "dummy")
&& (string.IsNullOrEmpty(args[1].Name) || args[1].Name == "dummy");
}
return false;
}
#endif
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 046b222c5a2e0994cb5c424ed912f808
timeCreated: 1536916211
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,272 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ModestTree;
using ModestTree.Util;
#if !NOT_UNITY3D
using UnityEngine.SceneManagement;
using UnityEngine;
#endif
namespace Zenject.Internal
{
public static class ZenUtilInternal
{
#if UNITY_EDITOR
static GameObject _disabledIndestructibleGameObject;
#endif
// Due to the way that Unity overrides the Equals operator,
// normal null checks such as (x == null) do not always work as
// expected
// In those cases you can use this function which will also
// work with non-unity objects
public static bool IsNull(System.Object obj)
{
return obj == null || obj.Equals(null);
}
#if UNITY_EDITOR
// This can be useful if you are running code outside unity
// since in that case you have to make sure to avoid calling anything
// inside Unity DLLs
public static bool IsOutsideUnity()
{
return AppDomain.CurrentDomain.FriendlyName != "Unity Child Domain";
}
#endif
public static bool AreFunctionsEqual(Delegate left, Delegate right)
{
return left.Target == right.Target && left.Method() == right.Method();
}
// Taken from here:
// http://stackoverflow.com/questions/28937324/in-c-how-could-i-get-a-classs-inheritance-distance-to-base-class/28937542#28937542
public static int GetInheritanceDelta(Type derived, Type parent)
{
Assert.That(derived.DerivesFromOrEqual(parent));
if (parent.IsInterface())
{
// Not sure if we can calculate this so just return 1
return 1;
}
if (derived == parent)
{
return 0;
}
int distance = 1;
Type child = derived;
while ((child = child.BaseType()) != parent)
{
distance++;
}
return distance;
}
#if !NOT_UNITY3D
public static IEnumerable<SceneContext> GetAllSceneContexts()
{
foreach (var scene in UnityUtil.AllLoadedScenes)
{
var contexts = scene.GetRootGameObjects()
.SelectMany(root => root.GetComponentsInChildren<SceneContext>()).ToList();
if (contexts.IsEmpty())
{
continue;
}
Assert.That(contexts.Count == 1,
"Found multiple scene contexts in scene '{0}'", scene.name);
yield return contexts[0];
}
}
public static void AddStateMachineBehaviourAutoInjectersInScene(Scene scene)
{
foreach (var rootObj in GetRootGameObjects(scene))
{
if (rootObj != null)
{
AddStateMachineBehaviourAutoInjectersUnderGameObject(rootObj);
}
}
}
// Call this before calling GetInjectableMonoBehavioursUnderGameObject to ensure that the StateMachineBehaviour's
// also get injected properly
// The StateMachineBehaviour's cannot be retrieved until after the Start() method so we
// need to use ZenjectStateMachineBehaviourAutoInjecter to do the injection at that
// time for us
public static void AddStateMachineBehaviourAutoInjectersUnderGameObject(GameObject root)
{
#if ZEN_INTERNAL_PROFILING
using (ProfileTimers.CreateTimedBlock("Searching Hierarchy"))
#endif
{
var animators = root.GetComponentsInChildren<Animator>(true);
foreach (var animator in animators)
{
if (animator.gameObject.GetComponent<ZenjectStateMachineBehaviourAutoInjecter>() == null)
{
animator.gameObject.AddComponent<ZenjectStateMachineBehaviourAutoInjecter>();
}
}
}
}
public static void GetInjectableMonoBehavioursInScene(
Scene scene, List<MonoBehaviour> monoBehaviours)
{
#if ZEN_INTERNAL_PROFILING
using (ProfileTimers.CreateTimedBlock("Searching Hierarchy"))
#endif
{
foreach (var rootObj in GetRootGameObjects(scene))
{
if (rootObj != null)
{
GetInjectableMonoBehavioursUnderGameObjectInternal(rootObj, monoBehaviours);
}
}
}
}
// NOTE: This method will not return components that are within a GameObjectContext
// It returns monobehaviours in a bottom-up order
public static void GetInjectableMonoBehavioursUnderGameObject(
GameObject gameObject, List<MonoBehaviour> injectableComponents)
{
#if ZEN_INTERNAL_PROFILING
using (ProfileTimers.CreateTimedBlock("Searching Hierarchy"))
#endif
{
GetInjectableMonoBehavioursUnderGameObjectInternal(gameObject, injectableComponents);
}
}
static void GetInjectableMonoBehavioursUnderGameObjectInternal(
GameObject gameObject, List<MonoBehaviour> injectableComponents)
{
if (gameObject == null)
{
return;
}
var monoBehaviours = gameObject.GetComponents<MonoBehaviour>();
for (int i = 0; i < monoBehaviours.Length; i++)
{
var monoBehaviour = monoBehaviours[i];
// Can be null for broken component references
if (monoBehaviour != null
&& monoBehaviour.GetType().DerivesFromOrEqual<GameObjectContext>())
{
// Need to make sure we don't inject on any MonoBehaviour's that are below a GameObjectContext
// Since that is the responsibility of the GameObjectContext
// BUT we do want to inject on the GameObjectContext itself
injectableComponents.Add(monoBehaviour);
return;
}
}
// Recurse first so it adds components bottom up though it shouldn't really matter much
// because it should always inject in the dependency order
for (int i = 0; i < gameObject.transform.childCount; i++)
{
var child = gameObject.transform.GetChild(i);
if (child != null)
{
GetInjectableMonoBehavioursUnderGameObjectInternal(child.gameObject, injectableComponents);
}
}
for (int i = 0; i < monoBehaviours.Length; i++)
{
var monoBehaviour = monoBehaviours[i];
// Can be null for broken component references
if (monoBehaviour != null
&& IsInjectableMonoBehaviourType(monoBehaviour.GetType()))
{
injectableComponents.Add(monoBehaviour);
}
}
}
public static bool IsInjectableMonoBehaviourType(Type type)
{
// Do not inject on installers since these are always injected before they are installed
return type != null && !type.DerivesFrom<MonoInstaller>() && TypeAnalyzer.HasInfo(type);
}
public static IEnumerable<GameObject> GetRootGameObjects(Scene scene)
{
#if ZEN_INTERNAL_PROFILING
using (ProfileTimers.CreateTimedBlock("Searching Hierarchy"))
#endif
{
if (scene.isLoaded)
{
return scene.GetRootGameObjects()
.Where(x => x.GetComponent<ProjectContext>() == null);
}
// Note: We can't use scene.GetRootObjects() here because that apparently fails with an exception
// about the scene not being loaded yet when executed in Awake
// We also can't use GameObject.FindObjectsOfType<Transform>() because that does not include inactive game objects
// So we use Resources.FindObjectsOfTypeAll, even though that may include prefabs. However, our assumption here
// is that prefabs do not have their "scene" property set correctly so this should work
//
// It's important here that we only inject into root objects that are part of our scene, to properly support
// multi-scene editing features of Unity 5.x
//
// Also, even with older Unity versions, if there is an object that is marked with DontDestroyOnLoad, then it will
// be injected multiple times when another scene is loaded
//
// We also make sure not to inject into the project root objects which are injected by ProjectContext.
return Resources.FindObjectsOfTypeAll<GameObject>()
.Where(x => x.transform.parent == null
&& x.GetComponent<ProjectContext>() == null
&& x.scene == scene);
}
}
#if UNITY_EDITOR
// Returns a Transform in the DontDestroyOnLoad scene (or, if we're not in play mode, within the current active scene)
// whose GameObject is inactive, and whose hide flags are set to HideAndDontSave. We can instantiate prefabs in here
// without any of their Awake() methods firing.
public static Transform GetOrCreateInactivePrefabParent()
{
if(_disabledIndestructibleGameObject == null || (!Application.isPlaying && _disabledIndestructibleGameObject.scene != SceneManager.GetActiveScene()))
{
var go = new GameObject("ZenUtilInternal_PrefabParent");
go.hideFlags = HideFlags.HideAndDontSave;
go.SetActive(false);
if(Application.isPlaying)
{
UnityEngine.Object.DontDestroyOnLoad(go);
}
_disabledIndestructibleGameObject = go;
}
return _disabledIndestructibleGameObject.transform;
}
#endif
#endif
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 401238e59d733ab48aaea1a582241b29
timeCreated: 1461708049
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,21 @@
using System;
using System.Diagnostics;
namespace Zenject
{
[DebuggerStepThrough]
[NoReflectionBaking]
public class ZenjectException : Exception
{
public ZenjectException(string message)
: base(message)
{
}
public ZenjectException(
string message, Exception innerException)
: base(message, innerException)
{
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 60bbf1e064ae9674185f3f301957c914
timeCreated: 1461708050
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,151 @@
#if !NOT_UNITY3D
using System;
using ModestTree;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Zenject
{
public enum LoadSceneRelationship
{
// This will use the ProjectContext container as parent for the new scene
// This is similar to just running the new scene normally
None,
// This will use current scene as parent for the new scene
// This will allow the new scene to refer to dependencies in the current scene
Child,
// This will use the parent of the current scene as the parent for the next scene
// In most cases this will be the same as None
Sibling
}
public class ZenjectSceneLoader
{
readonly ProjectKernel _projectKernel;
readonly DiContainer _sceneContainer;
public ZenjectSceneLoader(
[InjectOptional]
SceneContext sceneRoot,
ProjectKernel projectKernel)
{
_projectKernel = projectKernel;
_sceneContainer = sceneRoot == null ? null : sceneRoot.Container;
}
public void LoadScene(
string sceneName,
LoadSceneMode loadMode = LoadSceneMode.Single,
Action<DiContainer> extraBindings = null,
LoadSceneRelationship containerMode = LoadSceneRelationship.None,
Action<DiContainer> extraBindingsLate = null)
{
PrepareForLoadScene(loadMode, extraBindings, extraBindingsLate, containerMode);
Assert.That(Application.CanStreamedLevelBeLoaded(sceneName),
"Unable to load scene '{0}'", sceneName);
SceneManager.LoadScene(sceneName, loadMode);
// It would be nice here to actually verify that the new scene has a SceneContext
// if we have extra binding hooks, or LoadSceneRelationship != None, but
// we can't do that in this case since the scene isn't loaded until the next frame
}
public AsyncOperation LoadSceneAsync(
string sceneName,
LoadSceneMode loadMode = LoadSceneMode.Single,
Action<DiContainer> extraBindings = null,
LoadSceneRelationship containerMode = LoadSceneRelationship.None,
Action<DiContainer> extraBindingsLate = null)
{
PrepareForLoadScene(loadMode, extraBindings, extraBindingsLate, containerMode);
Assert.That(Application.CanStreamedLevelBeLoaded(sceneName),
"Unable to load scene '{0}'", sceneName);
return SceneManager.LoadSceneAsync(sceneName, loadMode);
}
void PrepareForLoadScene(
LoadSceneMode loadMode,
Action<DiContainer> extraBindings,
Action<DiContainer> extraBindingsLate,
LoadSceneRelationship containerMode)
{
if (loadMode == LoadSceneMode.Single)
{
Assert.IsEqual(containerMode, LoadSceneRelationship.None);
// Here we explicitly unload all existing scenes rather than relying on Unity to
// do this for us. The reason we do this is to ensure a deterministic destruction
// order for everything in the scene and in the container.
// See comment at ProjectKernel.OnApplicationQuit for more details
_projectKernel.ForceUnloadAllScenes();
}
if (containerMode == LoadSceneRelationship.None)
{
SceneContext.ParentContainers = null;
}
else if (containerMode == LoadSceneRelationship.Child)
{
if (_sceneContainer == null)
{
SceneContext.ParentContainers = null;
}
else
{
SceneContext.ParentContainers = new[] { _sceneContainer };
}
}
else
{
Assert.IsNotNull(_sceneContainer,
"Cannot use LoadSceneRelationship.Sibling when loading scenes from ProjectContext");
Assert.IsEqual(containerMode, LoadSceneRelationship.Sibling);
SceneContext.ParentContainers = _sceneContainer.ParentContainers;
}
SceneContext.ExtraBindingsInstallMethod = extraBindings;
SceneContext.ExtraBindingsLateInstallMethod = extraBindingsLate;
}
public void LoadScene(
int sceneIndex,
LoadSceneMode loadMode = LoadSceneMode.Single,
Action<DiContainer> extraBindings = null,
LoadSceneRelationship containerMode = LoadSceneRelationship.None,
Action<DiContainer> extraBindingsLate = null)
{
PrepareForLoadScene(loadMode, extraBindings, extraBindingsLate, containerMode);
Assert.That(Application.CanStreamedLevelBeLoaded(sceneIndex),
"Unable to load scene '{0}'", sceneIndex);
SceneManager.LoadScene(sceneIndex, loadMode);
// It would be nice here to actually verify that the new scene has a SceneContext
// if we have extra binding hooks, or LoadSceneRelationship != None, but
// we can't do that in this case since the scene isn't loaded until the next frame
}
public AsyncOperation LoadSceneAsync(
int sceneIndex,
LoadSceneMode loadMode = LoadSceneMode.Single,
Action<DiContainer> extraBindings = null,
LoadSceneRelationship containerMode = LoadSceneRelationship.None,
Action<DiContainer> extraBindingsLate = null)
{
PrepareForLoadScene(loadMode, extraBindings, extraBindingsLate, containerMode);
Assert.That(Application.CanStreamedLevelBeLoaded(sceneIndex),
"Unable to load scene '{0}'", sceneIndex);
return SceneManager.LoadSceneAsync(sceneIndex, loadMode);
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 097ddf2608210fe44a9d215a1721d857
timeCreated: 1461708048
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,40 @@
using ModestTree;
using UnityEngine;
namespace Zenject
{
public class ZenjectStateMachineBehaviourAutoInjecter : MonoBehaviour
{
DiContainer _container;
Animator _animator;
[Inject]
public void Construct(DiContainer container)
{
_container = container;
_animator = GetComponent<Animator>();
Assert.IsNotNull(_animator);
}
// The unity docs (https://unity3d.com/learn/tutorials/modules/beginner/5-pre-order-beta/state-machine-behaviours)
// mention that StateMachineBehaviour's should only be retrieved in the Start method
// which is why we do it here
public void Start()
{
// Animator can be null when users create GameObjects directly so in that case
// Just don't bother attempting to inject the behaviour classes
if (_animator != null)
{
var behaviours = _animator.GetBehaviours<StateMachineBehaviour>();
if (behaviours != null)
{
foreach (var behaviour in behaviours)
{
_container.Inject(behaviour);
}
}
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 486c69818dffcd14f96ce64502516bbb
timeCreated: 1527941118
licenseType: Free
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: -9991
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: