2010-05-24 40 views
2

我已经为允许可插入HTTP头检查器的HttpModule构建了一个通用配置系统。作为参考,这里是代码的基本布局 - 这应该足以感受一下我在做什么:RuntimeBinderException - C#.NET 4动态关键字 - 帮助我了解为什么方法不匹配

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通话的问题 - 工厂的所有实例提供的名称必须实现IHttpHeaderInspectingAuthenticatorFactor <>(如PostDeserialize中指定的)。因此,它们都将具有Construct方法,其中提供的类型T实际上是实现GetInspector()方法的类的实际类型。因此,例如,GetInspector将在BasicAuthenticationHeaderInspectorConfigurationElement的实例上调用 - 因此“this”将是BasicAuthenticationHeaderInspectorConfigurationElement的一个实例。

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

那么是什么给?我在这里没有得到什么?我尝试传递(这是动态的)或((HttpHeaderInspectingAuthenticatorConfigurationElement)) - 但都失败,同样的问题。

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通话变得

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

所以: -

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我已经解决这个问题,通过改变接口的架构一点点工作我认为在这里我的理解必定会有一个失误......希望有人能够阐明一些看法。

谢谢!

回答

-1

你是说:

dynamic factoryInstance = Activator.CreateInstance(Type.GetType(Factory)); 
dynamic parameter = this; 
return factoryInstance.Construct(parameter); 

没有工作?

+0

FAIL: dynamic factoryInstance = Activator.CreateInstance(Type.GetType(Factory)); return factoryInstance.Construct(this as dynamic); – 2010-08-05 15:15:15

+0

FAIL: dynamic factoryInstance = Activator.CreateInstance(Type.GetType(Factory)); return factoryInstance.Construct((HttpHeaderInspectingAuthenticatorConfigurationElement)this); – 2010-08-05 15:16:09

2

我认为你需要投入this作为动态。例如factoryInstance.Construct((dynamic)this);我认为问题是动态调用默认使用缓存委托(目标)签名的编译时间信息。

由于您的动态调用实现在基类中,因此它用于签名,但因为您的延迟签名是子类,所以您不能去HttpHeaderInspectingAuthenticatorConfigurationElementBasicAuthenticationHeaderInspectorConfigurationElement,动态参数告诉DLR参数类型是在运行时确定的。