StructureMap基于派生类型

时间:2018-01-29 23:10:44

标签: c# dependency-injection structuremap

我有两个实体基类:

public abstract class EntityBase { }
public abstract class ClientSpecificEntityBase : EntityBase

和两类实体:

public class Thing : EntityBase { }
public class ClientSpecificThing : ClientSpecificEntityBase { }

和两种类型的服务,它们都实现IService<T>

ServiceBase<T> : Service<T> where T : EntityBase
ClientSpecificServiceBase<T> : ServiceBase<T> where T : ClientSpecificEntityBase 

我正在使用以下代码配置StructureMap:

_.For(typeof(IService<>)).Use(typeof(ServiceBase<>));
_.For<IService<ClientSpecificEntityBase>>().Use<ClientSpecificServiceBase<ClientSpecificEntityBase>>();

但每次我尝试访问IService<ClientSpecificThing>

public ClientSpecificThingController(IService<ClientSpecificThing> service)

我收到ServiceBase<ClientSpecificThing>而不是ClientSpecificServiceBase<ClientSpecificThing>

有没有办法让StructureMap在映射ClientSpecificServiceBase<T>时包含派生类型?

1 个答案:

答案 0 :(得分:1)

不,你不能做你想做的事。容器不会通过已注册的组件查看泛型类型的基类。

如果您删除第一个注册,只留下

,这一点就会变得更加明显
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Foundation;
using UIKit;
using Xamarin.Forms.Platform.iOS;
using Xamarin.Forms;
using System.IO;
using WebKit;

[assembly: ExportRenderer(typeof(MyProject.HybridWebView), typeof(MyProject.iOS.HybridWebViewRenderer))]
namespace MyProject.iOS
{
    public class HybridWebViewRenderer : ViewRenderer<HybridWebView, WKWebView>, IWKScriptMessageHandler
    {
        const string JavaScriptFunction = @"var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta); function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
        WKUserContentController userController;

        protected override void     OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
        {
            base.OnElementChanged(e);

            if (Control == null)
            {
                userController = new WKUserContentController();
                var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
                userController.AddUserScript(script);
                userController.AddScriptMessageHandler(this, "invokeAction");

                var config = new WKWebViewConfiguration { UserContentController = userController };
                var webView = new WKWebView(Frame, config);
                SetNativeControl(webView);

                webView.Opaque = false;
                webView.BackgroundColor = UIColor.Clear;
                webView.ScrollView.ScrollEnabled = false;
                webView.ScrollView.Bounces = false;
            }
            if (e.OldElement != null)
            {
                userController.RemoveAllUserScripts();
                userController.RemoveScriptMessageHandler("invokeAction");
                var hybridWebView = e.OldElement as HybridWebView;
                hybridWebView.Cleanup();
            }
            if (e.NewElement != null)
            {
                string fileName = Path.Combine(NSBundle.MainBundle.BundlePath, string.Format("Content/{0}", Element.Uri));
                Control.LoadRequest(new NSUrlRequest(new NSUrl(fileName, false)));
            }
        }

        public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
        {
            Element.InvokeAction(message.Body.ToString());
        }
    }
}

现在,如果你打电话

_.For<IService<ClientSpecificEntityBase>>()
    .Use<ClientSpecificServiceBase<ClientSpecificEntityBase>>();

您将获得例外:

  

StructureMap.StructureMapConfigurationException:没有注册默认实例,无法自动确定类型&#39; IService&#39;

因此,并不是说StructureMap在两个注册之间混淆并且返回错误的注册。当你注册时,它并没有意识到:

var resolved = container.GetInstance<IService<ClientSpecificThing>>();

它可以使用它来实现这一点,因为一个泛型类型继承自另一个。

IService<ClientSpecificEntityBase>