[英]RuntimeBinderException - C# .NET 4 Dynamic Keyword - Help Me Understand Why Method Isn't Matching
我為HttpModule構建了一個通用的配置系統,允許可插入的HTTP頭檢查器。 作為參考,這里是代碼的基本布局 - 這應該足以讓我感覺到我在做什么:
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 - 因此'this'將是BasicAuthenticationHeaderInspectorConfigurationElement的實例。
但是,對Construct的調用失敗。 它找到方法很好,但顯然參數類型不匹配基於拋出的RuntimeBinderException。 基於CallSite.Target,看起來動態代理期望的預期類型是HttpHeaderInspectingAuthenticatorConfigurationElement - 我傳遞的'this'是從該基礎派生的BasicAuthenticationHeaderInspectorConfigurationElement。
什么給出了什么? 我在這里沒有得到什么嗎? 我嘗試傳遞(這是動態的)或((HttpHeaderInspectingAuthenticatorConfigurationElement)) - 但兩者都失敗了同樣的問題。
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)
僅供參考 - 我通過改變接口的架構來解決這個問題:
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);
}
所以我認為我的理解必定會有所失誤...希望有人可以解釋一下。
謝謝!
我認為你需要把this
變成動態的。 例如factoryInstance.Construct((dynamic)this);
我認為問題在於動態調用默認使用緩存委托(Target)簽名的編譯時信息。
由於動態調用的實現是在基類中,它是用於簽名的,但是因為你的后期綁定簽名是一個子類,你不能去HttpHeaderInspectingAuthenticatorConfigurationElement
- > BasicAuthenticationHeaderInspectorConfigurationElement
,因此通過將參數轉換為動態你告訴DLR參數類型是在運行時確定的。
你是這樣說的:
dynamic factoryInstance = Activator.CreateInstance(Type.GetType(Factory));
dynamic parameter = this;
return factoryInstance.Construct(parameter);
不工作?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.