RuntimeBinderException-C#.NET 4动态关键字-帮助我了解为什么方法不匹配 [英] RuntimeBinderException - C# .NET 4 Dynamic Keyword - Help Me Understand Why Method Isn't Matching

查看:121
本文介绍了RuntimeBinderException-C#.NET 4动态关键字-帮助我了解为什么方法不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我为HttpModule构建了一个通用的配置系统,该系统允许可插入的HTTP标头检查器。作为参考,下面是代码的基本布局-这应该足以使我对正在做的事情有所了解:

I've built a generic config system for an HttpModule that allows pluggable HTTP header inspectors. For reference, here is the basic layout of the code -- this should be enough to get a feel for what I'm doing:

public interface IHttpHeaderInspectingAuthenticatorFactory<T>
    where T: HttpHeaderInspectingAuthenticatorConfigurationElement
{
    IHttpHeaderInspectingAuthenticator<T> Construct(T config);
}

public class BasicAuthenticationInspectingAuthenticatorFactory :
    IHttpHeaderInspectingAuthenticator<BasicAuthenticationHeaderInspectorConfigurationElement>
{
    public IHttpHeaderInspectingAuthenticator<BasicAuthenticationHeaderInspectorConfigurationElement> Construct(BasicAuthenticationHeaderInspectorConfigurationElement config)
    {
        return new BasicAuthenticationInspectingAuthenticator(config);
    }
}

public class BasicAuthenticationInspectingAuthenticator : HttpHeaderInspectingAuthenticatorBase<BasicAuthenticationHeaderInspectorConfigurationElement>
{
    internal BasicAuthenticationInspectingAuthenticator(BasicAuthenticationHeaderInspectorConfigurationElement config) 
        : base(config) {}

 //snip -- IHttpHeaderInspectingAuthenticator<T> and IHttpHeaderInspectingAuthenticator implementation
}


public class BasicAuthenticationHeaderInspectorConfigurationElement : HttpHeaderInspectingAuthenticatorConfigurationElement
{
 //extra properties
}


public class HttpHeaderInspectingAuthenticatorConfigurationElement : ConfigurationElement
{
 protected override void PostDeserialize()
 {
     base.PostDeserialize();

     //simple verification of info supplied in config
     var t = Type.GetType(Factory);
     if (null == t)
         throw new ConfigurationErrorsException(String.Format("The factory type specified [{0}] cannot be found - check configuration settings", Factory ?? ""));

     if (!typeof(IHttpHeaderInspectingAuthenticatorFactory<>).IsGenericInterfaceAssignableFrom(t))
         throw new ConfigurationErrorsException(String.Format("The factory type specified [{0}] must derive from {1} - check configuration settings", Factory ?? "", typeof(IHttpHeaderInspectingAuthenticatorFactory<>).Name));

     var c = t.GetConstructor(Type.EmptyTypes);
     if (null == c)
         throw new ConfigurationErrorsException(String.Format("The factory type specified [{0}] must have a parameterless constructor - check configuration settings", Factory ?? ""));
 }

 [ConfigurationProperty("factory", IsRequired = true)]
 public string Factory
 {
  get { return (string)this["factory"]; }
  set { this["factory"] = value; }
 }

 //this allows us to use types derived from HttpHeaderInspectingAuthenticatorConfigurationElement
    protected override bool OnDeserializeUnrecognizedAttribute(string name, string value)
    {                    
        ConfigurationProperty property = new ConfigurationProperty(name, typeof(string), value);
        Properties.Add(property);
        base[property] = value;            
        return true;
    }

 public IHttpHeaderInspectingAuthenticator GetInspector()
 {
     dynamic factoryInstance = Activator.CreateInstance(Type.GetType(Factory));
     return factoryInstance.Construct(this);
 }
}

现在问题出现在GetInspector调用中-全部提供的Factory名称的实例必须实现IHttpHeaderInspectingAuthenticatorFactor<>(按照PostDeserialize中的说明)。因此,它们都将具有一个Construct方法,其中提供的T类型实际上是实现GetInspector()方法的类的实际类型。因此,例如,将在BasicAuthenticationHeaderInspectorConfigurationElement实例上调用GetInspector,因此这将是BasicAuthenticationHeaderInspectorConfigurationElement的实例。

Now the problem occurs in the GetInspector call -- all instances of the Factory name supplied must implement IHttpHeaderInspectingAuthenticatorFactor<> (as spec'd in PostDeserialize). Therefore, they will all have a Construct method, where the type T supplied will actually be the actual type of the class implementing the GetInspector() method. So for instance, GetInspector will be called on an instance of BasicAuthenticationHeaderInspectorConfigurationElement -- so 'this' will be an instance of BasicAuthenticationHeaderInspectorConfigurationElement.

但是,对Construct的调用失败。它发现方法很好,但是显然基于抛出的RuntimeBinderException,参数类型不匹配。根据CallSite.Target的显示,动态代理期望的期望类型是HttpHeaderInspectingAuthenticatorConfigurationElement-我传递的 this是从该基础派生的BasicAuthenticationHeaderInspectorConfigurationElement。

However, the call to Construct fails. It finds the method fine, but apparently the parameter type is NOT matching up based on the RuntimeBinderException thrown. It would appear, based on the CallSite.Target that the expected type that the dynamic proxy expects is HttpHeaderInspectingAuthenticatorConfigurationElement -- the 'this' I'm passing is a BasicAuthenticationHeaderInspectorConfigurationElement, derived from that base.

那有什么用呢?我在这里没有东西吗?我尝试传递(这是动态的)或((HttpHeaderInspectingAuthenticatorConfigurationElement)this),但是都失败,并出现相同的问题。

So what gives? Am I not getting something here? I tried passing (this as dynamic) or ((HttpHeaderInspectingAuthenticatorConfigurationElement)this) -- but both fail with the same problem.

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: The best overloaded method match for 'Redcated.Authentication.BasicAuthenticationInspectingAuthenticatorFactory.Construct(Redcated.Authentication.Configuration.BasicAuthenticationHeaderInspectorConfigurationElement)' has some invalid arguments
  at CallSite.Target(Closure , CallSite , Object , HttpHeaderInspectingAuthenticatorConfigurationElement )
  at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
  at Redcated.Authentication.Configuration.HttpHeaderInspectingAuthenticatorConfigurationElement.GetInspector() in D:\Users\ebrown\Documents\Visual Studio 2010\Projects\Utility\source\Authentication Library\Configuration\HttpHeaderInspectingAuthenticatorConfigurationElement.cs:line 79
  at Redcated.Authentication.Configuration.HttpHeaderInspectingAuthenticatorConfigurationElementCollection.<GetInspectors>b__0(HttpHeaderInspectingAuthenticatorConfigurationElement i) in D:\Users\ebrown\Documents\Visual Studio 2010\Projects\Utility\source\Authentication Library\Configuration\HttpHeaderInspectingAuthenticatorConfigurationElementCollection.cs:line 78
  at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
  at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
  at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector)
  at Redcated.Authentication.HttpHeaderInspectingAuthenticationModule.AuthenticateRequest(Object sender, EventArgs e) in D:\Users\ebrown\Documents\Visual Studio 2010\Projects\Utility\source\Authentication Library\HttpHeaderInspectingAuthenticationModule.cs:line 49
  at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
  at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)



FYI-我通过更改接口的体系结构来解决此问题:

FYI -- I have worked around this issue by altering the architecture of the interfaces a tad:

public interface IHttpHeaderInspectingAuthenticatorFactory
{
    IHttpHeaderInspectingAuthenticator Construct(HttpHeaderInspectingAuthenticatorConfigurationElement config);
}

public interface IHttpHeaderInspectingAuthenticatorFactory<T> : IHttpHeaderInspectingAuthenticatorFactory
    where T: HttpHeaderInspectingAuthenticatorConfigurationElement
{
    IHttpHeaderInspectingAuthenticator<T> Construct(T config);
}

public abstract class HttpHeaderInspectingAuthenticatorFactoryBase<T> : IHttpHeaderInspectingAuthenticatorFactory<T>
            where T : HttpHeaderInspectingAuthenticatorConfigurationElement
{
    protected static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

    public abstract IHttpHeaderInspectingAuthenticator<T> Construct(T config);

    public IHttpHeaderInspectingAuthenticator Construct(HttpHeaderInspectingAuthenticatorConfigurationElement config)
    {
        return Construct((T)config);
    }
}

 public class BasicAuthenticationInspectingAuthenticatorFactory :
    HttpHeaderInspectingAuthenticatorFactoryBase<BasicAuthenticationHeaderInspectorConfigurationElement>
{
    public override IHttpHeaderInspectingAuthenticator<BasicAuthenticationHeaderInspectorConfigurationElement> Construct(BasicAuthenticationHeaderInspectorConfigurationElement config)
    {
        return new BasicAuthenticationInspectingAuthenticator(config);
    }
}

然后,当然,GetInspector调用变为

And then of course, the GetInspector call becomes

public IHttpHeaderInspectingAuthenticator GetInspector()
{
    var factoryInstance = (IHttpHeaderInspectingAuthenticatorFactory)Activator.CreateInstance(Type.GetType(Factory));
    return factoryInstance.Construct(this);
}

所以我认为我的理解一定有失误...希望

So I assume there must be a lapse in my understanding here... hoping someone can shed some light.

谢谢!

推荐答案

您需要将 this 强制转换为动态。例如, factoryInstance.Construct((dynamic)this); 我认为问题在于动态调用默认使用编译时信息作为缓存委托(目标)的签名

I think you need to cast this as dynamic. for example factoryInstance.Construct((dynamic)this); I think the issue is that the dynamic invocation uses compile time information for the cached delegate (Target)'s signature by default.

由于动态调用的实现在基类中,因此它是用于签名的内容,但是由于后期绑定签名是子类,因此您可以' t转到 HttpHeaderInspectingAuthenticatorConfigurationElement -> BasicAuthenticationHeaderInspectorConfigurationElement ,通过将参数强制转换为动态,您将告诉DLR参数类型是在运行时确定的。

Since you implementation of the dynamic call is in the base class it is what it is using for the signature, but because your late bound signature is a subclass you can't go HttpHeaderInspectingAuthenticatorConfigurationElement -> BasicAuthenticationHeaderInspectorConfigurationElement, there fore by casting the argument to dynamic you are telling the DLR that the arguments type is determined at runtime.

这篇关于RuntimeBinderException-C#.NET 4动态关键字-帮助我了解为什么方法不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆