Как я могу автоматически разрешать зависимости С#?
Я читал об инъекции зависимостей Unity, и я это понимаю, и это позволяет вам вводить класс в интерфейс. Мне любопытно, есть ли у меня? В приведенном ниже сценарии есть TerrainGenerator
и TileCreator
в том же пространстве. Как я могу получить TileCreator
внутри генератора в качестве зависимости?
![введите описание изображения здесь]()
http://geekswithblogs.net/danielggarcia/archive/2014/01/23/introduction-to-dependency-injection-with-unity.aspx позволяет мне регистрировать тип, но я где-то читал, что пока класс видится в разделе Unity Assets, он я смогу автоматически вводить его, я просто не могу понять синтаксис (если это возможно).
Обновление
Я мог бы поместить все классы в один файл... с большой системой, которая может быть довольно раздражающей. В то же время это подход, который я попробую - лучше, чем его вообще не работать.
Обновление
Похоже, что Unity должен иметь возможность смотреть на конструктор класса и выполнять эти разрешения автоматически и вводить их в конструктор моего класса. Возможно ли это?
Ответы
Ответ 1
Если вы ищете DI для движка Unity3d, возможно, это сработает (я его не использовал, но обратная связь положительная) https://github.com/modesttree/Zenject
Если вы говорите о библиотеке Microsoft Unity DI, вы должны это сделать:
container.RegisterTypes(
AllClasses.FromLoadedAssemblies(),
WithMappings.FromMatchingInterface,
WithName.Default);
Ответ 2
Я всегда использую следующий код. Когда я загружаю приложение, приложение просматривает каталог для всех Dll. Таким образом, когда вы загружаете класс с отражением, он ищет Dll и exes. Вы также можете добавить еще несколько путей для поиска.
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(currentDomain_AssemblyResolve);
Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string defaultFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string assemblyName = new AssemblyName(args.Name).Name;
string assemblyNameDll = assemblyName + ".dll";
string assemblyNameExe = assemblyName + ".exe";
string assemblyPathDll = Path.Combine(defaultFolder, assemblyNameDll);
string assemblyPathExe = Path.Combine(defaultFolder, assemblyNameExe);
string assemblyPathToUse = null;
if (File.Exists(assemblyPathDll))
{
assemblyPathToUse = assemblyPathExe;
}
else if (File.Exists(assemblyPathExe))
{
assemblyPathToUse = assemblyPathExe;
}
else
{
IEnumerable<string> merge = AssemblyFolders.Values;
if (!string.IsNullOrEmpty(TempLoadingFolder))
{
merge = AssemblyFolders.Values.Union(new List<string>() { TempLoadingFolder });
}
foreach (var folder in merge)
{
assemblyPathDll = Path.Combine(folder, assemblyNameDll);
assemblyPathExe = Path.Combine(folder, assemblyNameExe);
if (File.Exists(assemblyPathDll))
{
assemblyPathToUse = assemblyPathDll;
break;
}
else if (File.Exists(assemblyPathExe))
{
assemblyPathToUse = assemblyPathExe;
break;
}
}
}
Assembly assembly = null;
if (assemblyPathToUse != null && File.Exists(assemblyPathToUse))
{
assembly = Assembly.LoadFrom(assemblyPathToUse);
}
return assembly;
}
Ответ 3
Нет, вам не нужно использовать интерфейсы, вы также можете регистрировать и разрешать конкретные типы.
Например, вы можете зарегистрировать TerrainGenerator и TileCreator следующим образом:
var myTileCreator = new TileCreator();
container.RegisterType<TerrainGenerator>(new PerThreadLifetimeManager(), new InjectionFactory(c => new TerrainGenerator(myTileCreator)));
Чтобы решить TerrainGenerator:
TerrainGenerator generator = container.Resolve<TerrainGenerator>();
Чтобы решить TerrainGenerator с помощью другого TileCreator:
TerrainGenerator generator = container.Resolve<TerrainGenerator>(new ParameterOverride("tileCreator", new TileCreator()));
Вы можете прочитать Injection Dependency с Unity - Patterns and Practices для получения более полезной информации, такой как инъекции свойств и т.п.
Надеюсь, что это поможет.
Ответ 4
Не думайте, что это важно, если у вас есть классы в одном файле или нет. Единство должно знать, как создать экземпляр с учетом типа.
Если используется RegisterInstance, конкретный объект, переданный как аргумент, возвращается каждый раз, когда вызывается Resolve для типа. Если тип зарегистрирован с использованием RegisterType (или вообще не зарегистрирован для конкретных классов), Unity попытается создать экземпляр типа с помощью конструктора с большим количеством аргументов. Для каждого из типов параметров Unity попытается их рекурсивно разрешить.
Регистрация сопоставлений для типов интерфейсов для конкретных типов является обязательной, но сами записи конкретных типов необязательны.
Пример кода:
using Microsoft.Practices.Unity;
using System;
namespace Unity
{
interface IFooBar
{
string Message();
}
class Foo
{
string msg;
public Foo()
{
msg = "Hello";
}
public override string ToString()
{
return msg;
}
}
class Bar
{
private Foo _f;
private IFooBar _fb;
public Bar(Foo f, IFooBar fb)
{
this._f = f;
this._fb = fb;
}
public override string ToString()
{
return _f.ToString() + " World " + _fb.Message();
}
}
class FooBar : IFooBar
{
public string Message()
{
return "Unity!";
}
}
class Program
{
static void Main(string[] args)
{
UnityContainer container = new UnityContainer();
container.RegisterType<IFooBar, FooBar>(); // required
container.RegisterType<Foo>(); // optional
container.RegisterType<Bar>(); // optional
var mybar = container.Resolve<Bar>();
Console.WriteLine(mybar);
}
}
}
https://msdn.microsoft.com/en-us/library/microsoft.practices.unity.iunitycontainer_methods(v=pandp.20).aspx