【问题标题】:How do I resolve C# dependencies automatically?如何自动解决 C# 依赖项?
【发布时间】:2016-06-14 04:05:18
【问题描述】:

我一直在阅读有关 Unity 的依赖注入的信息,我知道这是一回事,它允许您将类键入到接口中。我很好奇的是,我必须这样做吗?在下面的场景中,TerrainGeneratorTileCreator 在同一个空间中。如何在生成器中获取 TileCreator 作为依赖项?

http://geekswithblogs.net/danielggarcia/archive/2014/01/23/introduction-to-dependency-injection-with-unity.aspx 引导我注册一个类型,但我在某处读到,只要该类在 Unity Assets 部分可见,它就能够自动注入它,我只是无法弄清楚语法(如果可能的话)。

更新

可以将所有类放在一个文件中...使用一个可能很烦人的大型系统。同时,这是我会尝试的一种方法 - 总比完全不起作用要好。

更新 似乎 Unity 应该能够查看类的构造函数并自动执行这些解析并将它们注入我的类的构造函数中。这可能吗?

【问题讨论】:

  • 你确定unity3d 有依赖注入吗?你确定你没有读过微软同样命名的unity吗?您链接到的链接是在谈论 Microsoft's Unity,而不是 Unity Technologies 的 Unity。目前尚不清楚您要实现的目标,您能否详细解释一下您要实现的目标?
  • 我肯定在问 Unity3d,我没有意识到这是两个不同的东西。感谢您指出这一点。
  • 你不应该碰MonoBehavior类的构造函数。您的问题过于集中在使依赖注入工作上,而您没有充分解释为什么首先需要使依赖注入工作,这被称为@ 987654326@,重新处理您的问题并添加有关您遇到的真正问题的更多详细信息(“在同一个空间中有一个 TerrainGenerator 和 TileCreator”),人们将能够帮助您...
  • 依赖注入在 Unity3d 中不是必需的,在 Unity 的系统中有“更合适”的方法来处理它,但如果没有更多关于你到底是什么的详细信息,我们无法告诉你哪种方法是正确的尝试做。
  • @ScottChamberlain 有问题的类会生成地形。随着时间的推移,它还会放置树木、不同类型的资源等资产,并确定给定的地形是否为水。我试图避免所有这些逻辑都在一个嵌套的类中。

标签: c# unity3d


【解决方案1】:

如果您正在为 Unity3d 引擎寻找 DI,也许这会起作用(我没有使用过,但反馈是积极的)https://github.com/modesttree/Zenject

如果你说的是微软的 Unity DI 库,你应该可以这样做:

container.RegisterTypes(
    AllClasses.FromLoadedAssemblies(),
    WithMappings.FromMatchingInterface,
    WithName.Default);

【讨论】:

  • 宾果游戏,这就是我想要的。感谢您强调这样一个干净的解决方案。我仍然希望它足够聪明,可以查看类的构造函数并自动构建该类的依赖项
【解决方案2】:

我总是使用以下代码。当我加载应用程序时,应用程序会在目录中查找所有 Dll。这样,当您使用反射加载类时,它会搜索 Dll 和 exe。您还可以添加更多搜索路径。

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

    不要认为在同一个文件中是否有这些类并不重要。 Unity 需要知道如何创建给定类型的实例。

    如果使用 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

    【讨论】:

      【解决方案4】:

      不,您不必使用接口,您也可以注册和解析具体类型。

      例如,您可以如下注册TerrainGeneratorTileCreator

      var myTileCreator = new TileCreator();
      container.RegisterType<TerrainGenerator>(new PerThreadLifetimeManager(), new InjectionFactory(c => new TerrainGenerator(myTileCreator)));
      

      解决TerrainGenerator

      TerrainGenerator generator = container.Resolve<TerrainGenerator>();
      

      用不同的TileCreator解析TerrainGenerator

      TerrainGenerator generator = container.Resolve<TerrainGenerator>(new ParameterOverride("tileCreator", new TileCreator()));
      

      您可能需要阅读Dependency Injection with Unity - Patterns and Practices 以了解更多有用的信息,例如属性注入等。

      希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 2015-03-01
        • 2014-04-14
        • 1970-01-01
        • 2016-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多