gpt4 book ai didi

c# - RuntimeBinderException - C# .NET 4 动态关键字 - 帮助我理解为什么方法不匹配

转载 作者:行者123 更新时间:2023-11-30 16:33:48 25 4
gpt4 key购买 nike

我为 HttpModule 构建了一个通用配置系统,它允许可插入的 HTTP header 检查器。作为引用,这里是代码的基本布局——这应该足以让我了解我在做什么:

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() 方法的类的实际类型。因此,例如,将在 BasicAuthenticationHeaderInspectorConfigurationElement 的实例上调用 GetInspector——因此“this”将是 BasicAuthenticationHeaderInspectorConfigurationElement 的实例。

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

那么是什么给了?我在这里没有得到什么吗?我尝试传递(this as dynamic)或((HttpHeaderInspectingAuthenticatorConfigurationElement)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)

仅供引用——我已经通过稍微改变接口(interface)的架构来解决这个问题:

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); 我认为问题是动态调用默认使用缓存委托(delegate)(目标)签名的编译时信息。

因为动态调用的实现是在基类中,它是它用于签名的,但是因为你的后期绑定(bind)签名是一个子类,你不能去 HttpHeaderInspectingAuthenticatorConfigurationElement -> BasicAuthenticationHeaderInspectorConfigurationElement,因此通过将参数转换为 dynamic,您告诉 DLR 参数类型是在运行时确定的。

关于c# - RuntimeBinderException - C# .NET 4 动态关键字 - 帮助我理解为什么方法不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2898307/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com