动态委托将方法作为参数传递给C#

时间:2012-11-24 11:44:27

标签: c# dynamic

有没有办法使用DLR引用C#中的方法?

在JavaScript或Python等动态语言中,我可以轻松地将方法作为参数传递给另一个方法。在C#中是静态类型语言,我要么使用需要大量转换的Delegate类型:

public static void AddMethod(Delegate del)
{
    // implementation
}

然后在我调用此方法时使用转换

static void Main(string[] args)
{
    AddMethod(new Func<object, bool>(Test));
}

public static bool Test(object obj)
{
    return true;
}

或者,我需要定义几十个重载来满足任何方法调用:

public static void AddMethod<TResult>(Func<TResult> method)
{
}

public static void AddMethod<T, TResult>(Func<T, TResult> method)
{
}

public static void AddMethod<T1, T2, TResult>(Func<T1, T2, TResult> method)
{
}

public static void AddMethod<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> method)
{
}

有没有更简洁的方法将参数定义为所有其他方法的占位符? (我在这里试图避免MethodInfo或其他Reflection内容。

我正在尝试这样的事情:

public delegate dynamic DynamicDelegate(params dynamic[] args);

public static void AddMethod(DynamicDelegate method)
{
}

但编译器似乎不接受动态声明的委托的静态类型方法!

还有其他想法吗?

3 个答案:

答案 0 :(得分:2)

您可以使用简单的Action

void AddMethod(Action action) //or void AddMethod(Func<TResult> fxn)
{
}

并致电

AddMethod(()=>Test(obj));   

AddMethod(()=>Test(obj1,obj2));   

- 编辑 -

AddMethod(() => Math.Max(1,3));  
AddMethod(() => (int)Math.Sqrt(4));
AddMethod(() => new int[]{8,5,6}.Min())

void AddMethod(Func<int> fxn)
{
     int i = fxn() * fxn();  // <---
}

答案 1 :(得分:2)

由于.NET不允许具有未知参数语法的委托(这将近似C void指针,这不是您想要的类型安全语言),允许变量参数列表的最接近的事情是传递一个对象参数数组(即object MyMethod(params object[] args)) 但是,由于此数组也是对象引用,因此您可以使用单个对象引用:

object MyMethod(object arg))

.NET框架也这样做,参见例如ParameterizedThreadStart delegate)

因此,基本思想是您要求用户将其代码编写为与上述签名匹配的方法,然后它可以接收任何类型或大小的任何变量参数列表。

答案 2 :(得分:0)

见下文

    public delegate dynamic Reference(params dynamic[] args);

    public class PassByReference
    {
        Reference reference;

        public PassByReference(Reference reference)
        {
            this.reference = reference;
        }
        public override string ToString()
        {
            return this.reference().ToString();
        }
    }

    public class Logger
    {

        static Dictionary<string, Logger> logFormatDict = new Dictionary<string, Logger>();
        private List<LoggerDelegate> loggerDelegates = new List<LoggerDelegate>();
        public static Logger GetLogger(string name)
        {
            if (logFormatDict.ContainsKey(name))
            {
                return logFormatDict[name];
            }
            else
            {
                var newLogFormat = new Logger(name, "");
                logFormatDict.Add(name, newLogFormat);
                return newLogFormat;
            }
        }

        private event LoggerDelegate loggingEvent;
        private Logger(string name, string format, params dynamic[] args)
        {
            this.Name = name;
            this.format = format;
            this.args = args;
        }
        public void AddLogger(LoggerDelegate logger)
        {
            if (!loggerDelegates.Contains(logger))
            {
                loggingEvent += logger;
                loggerDelegates.Add(logger);
            }
        }

        public void RemoveLogger(LoggerDelegate logger)
        {
            if (loggerDelegates.Contains(logger))
            {
                loggingEvent -= logger;
                loggerDelegates.Remove(logger);
            }
        }

        public void Log(string text, params dynamic[] args)
        {
            this.Invoke(String.Format(text, args));
        }

        public void Invoke(string text, params dynamic[] args)
        {
            loggingEvent.Invoke(this.ToString() + text, args);
        }


        public void SetFormat(string format, params dynamic[] args)
        {
            this.args = args;
            this.format = format;
        }
        public string Name
        {
            get;
            set;
        }
        string format;
        dynamic[] args;

        public override string ToString()
        {
            return String.Format(format, args);
        }
    }

transform: translate(0, -50%);