5

有没有办法使用 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)
{
}

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

还有其他想法吗?

4

3 回答 3

4

你可以使用一个简单的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();  // <---
}
于 2012-11-24T11:57:21.633 回答
2

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

object MyMethod(object arg))

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

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

于 2012-11-24T12:53:07.557 回答
0

见下文

    Logger coreLogger;
    Logger coreErrorLogger;

    public Core()
    {
        PassByReference timestamp = new PassByReference(Timestamp);

        coreLogger = Logger.GetLogger("LiTHiuM Core");
        coreLogger.SetFormat("[{0}][LiTHiuM Core]: ", timestamp);
        coreLogger.AddLogger(Log);


        coreErrorLogger = Logger.GetLogger("LiTHiuM Core Error");
        coreErrorLogger.SetFormat("[{0}][LiTHiuM Core (ERROR)]: ", timestamp);
        coreErrorLogger.AddLogger(Error);

    }

    public string Timestamp(params dynamic[] args)
    {
        return DateTime.Now.ToString();
    }
    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);
        }
    }

于 2020-06-01T23:32:43.987 回答