C# 从一个代理转换为另一个代理。假石膏

C# 从一个代理转换为另一个代理。假石膏,c#,.net,delegates,C#,.net,Delegates,我们正在使用IoC,并将我们的日志记录与它一起公开。我们正在使用Common.Logging,我已经为Common.Logging.FormatMessageHandler编写了一个匹配的委托,但我不知道如何将该委托的版本转换为Common.Loggingapi所期望的版本 这个问题看起来很相似,但我不明白如何将我的实现类型转换为我想要调用的已知类型。 这是我的代表签名: public delegate string FormatMessageHandler(string format, pa

我们正在使用IoC,并将我们的日志记录与它一起公开。我们正在使用
Common.Logging
,我已经为
Common.Logging.FormatMessageHandler
编写了一个匹配的委托,但我不知道如何将该委托的版本转换为
Common.Logging
api所期望的版本

这个问题看起来很相似,但我不明白如何将我的实现类型转换为我想要调用的已知类型。

这是我的代表签名:

public delegate string FormatMessageHandler(string format, params object[] args)
以下是常见的日志记录:

public delegate string FormatMessageHandler(string format, params object[] args)

相同的名称(并不重要)和相同数量的参数。这两者在编译时都是已知的,所以应该是显而易见的,但我没有看到。

如果完全相同,为什么不首先使用Common.Logging的委托?
但是,您的问题的一个孤立点是,要么使用您提到的问题中链接的文章中解释的动态强制转换,要么这样做:

YourNamespace.FormatMessageHandler yourHandler = ...;
Common.Logging.FormatMessageHandler handler = (f, a) => yourHandler(f, a);
更新:
根据你的评论,你想要这样的东西:

public void Error(Action<Your.FormatMessageHandler> formatMessageCallback)
{
    _logger.Error(h => formatMessageCallback((f, a) => h(f, a)));
}
公共无效错误(操作formatMessageCallback)
{
_错误(h=>formatMessageCallback((f,a)=>h(f,a));
}

这将创建一个新操作,其中包含一个类型为
Common.Logging.FormatMessageHandler
的参数
h
,该参数调用提供的操作
formatMessageCallback
,并使用一个新委托
Your.FormatMessageHandler
,该委托接受两个参数
f
a
。这个新的委托依次使用提供的两个参数调用
h

您可以手动执行此操作,但它与转换时涉及的反射一样昂贵。转换代理后,其行为基本相同

internal class Program
{
    //An example delegate target
    static void Click(object o, EventArgs e) { }

    //A simple test method
    static void Main(string[] args)
    {
        EventHandler onclick = Click;
        EventHandler<EventArgs> converted;
        if (!TryConvertDelegate(onclick, out converted))
            throw new Exception("failed");
    }

    //The conversion of one delegate type to another
    static bool TryConvertDelegate<TOldType, TNewType>(TOldType oldDelegate, out TNewType newDelegate)
        where TOldType : class, System.ICloneable, System.Runtime.Serialization.ISerializable
        where TNewType : class, System.ICloneable, System.Runtime.Serialization.ISerializable
    {
        if (!typeof(Delegate).IsAssignableFrom(typeof(TOldType)) || !typeof(Delegate).IsAssignableFrom(typeof(TNewType)))
            throw new ArgumentException(); //one of the types is not a delegate

        newDelegate = default(TNewType);
        Delegate handler = oldDelegate as System.Delegate;
        if (handler == null)
            return true; //null in, null out

        Delegate result = null;
        foreach (Delegate d in handler.GetInvocationList())
        {
            object copy = System.Delegate.CreateDelegate(typeof(TNewType), d.Target, d.Method, false);
            if (copy == null)
                return false; // one or more can not be converted
            result = System.Delegate.Combine(result, (System.Delegate)copy);
        }
        newDelegate = result as TNewType;
        return (newDelegate != null);
    }
内部类程序
{
//一个示例委托目标
静态空单击(对象o,事件参数e){}
//一种简单的测试方法
静态void Main(字符串[]参数)
{
EventHandler onclick=单击;
EventHandler已转换;
如果(!tryconvertdegate(onclick,out-converted))
抛出新异常(“失败”);
}
//将一种委托类型转换为另一种委托类型
静态布尔TryConvertDelegate(TOldType oldDelegate,out TNewType newDelegate)
其中TOldType:class、System.iClonable、System.Runtime.Serialization.ISerializable
其中TNewType:class,System.ICloneable,System.Runtime.Serialization.ISerializable
{
如果(!typeof(Delegate).IsAssignableFrom(typeof(TOldType))| |!typeof(Delegate).IsAssignableFrom(typeof(TNewType)))
抛出新ArgumentException();//其中一个类型不是委托
newDelegate=默认值(TNewType);
委托处理程序=作为System.Delegate的旧委托;
if(handler==null)
返回true;//输入为null,输出为null
委托结果=空;
foreach(handler.GetInvocationList()中的委托d)
{
对象副本=System.Delegate.CreateDelegate(typeof(TNewType),d.目标,d.方法,false);
if(copy==null)
return false;//无法转换一个或多个
结果=System.Delegate.Combine(结果,(System.Delegate)副本);
}
newDelegate=结果为TNewType;
返回(newDelegate!=null);
}

您的解释非常好,在我尝试使用该操作之前一直有效。如何使用该操作?我的方法签名:public void Error(Action formatMessageCallback),要调用的最后一个方法是:void Common.Logging.Error(Action formatMessageCallback);我不会公开Common.Logging委托或任何API,以防我们决定将来使用不同的日志框架。如果发生这种情况,则“全部”我们要做的是编写一些代码来实现我们以前定义的日志接口,并包装对新日志框架的调用。@David:不使用日志记录器的委托的原因是有效的,感谢您的解释。请参阅更新以获取您第一条评论的解决方案。