如何在dart中获取当前调用函数的名称?

ten*_*sai 2 reflection web dart

C#具有:

System.Reflection.MethodBase.GetCurrentMethod()。名称

Dart是否具有类似的功能,但是会返回当前正在运行的函数以及调用当前正在运行的函数的名称的结果。

Hol*_*fox 14

稍微整理一下@LuisDev99的答案,为自己优化:

class LoggerStackTrace {
  const LoggerStackTrace._({
    required this.functionName,
    required this.callerFunctionName,
    required this.fileName,
    required this.lineNumber,
    required this.columnNumber,
  });

  factory LoggerStackTrace.from(StackTrace trace) {
    final frames = trace.toString().split('\n');
    final functionName = _getFunctionNameFromFrame(frames[0]);
    final callerFunctionName = _getFunctionNameFromFrame(frames[1]);
    final fileInfo = _getFileInfoFromFrame(frames[0]);

    return LoggerStackTrace._(
      functionName: functionName,
      callerFunctionName: callerFunctionName,
      fileName: fileInfo[0],
      lineNumber: int.parse(fileInfo[1]),
      columnNumber: int.parse(fileInfo[2].replaceFirst(')', '')),
    );
  }

  final String functionName;
  final String callerFunctionName;
  final String fileName;
  final int lineNumber;
  final int columnNumber;

  static List<String> _getFileInfoFromFrame(String trace) {
    final indexOfFileName = trace.indexOf(RegExp('[A-Za-z]+.dart'));
    final fileInfo = trace.substring(indexOfFileName);

    return fileInfo.split(':');
  }

  static String _getFunctionNameFromFrame(String trace) {
    final indexOfWhiteSpace = trace.indexOf(' ');
    final subStr = trace.substring(indexOfWhiteSpace);
    final indexOfFunction = subStr.indexOf(RegExp('[A-Za-z0-9]'));

    return subStr
        .substring(indexOfFunction)
        .substring(0, subStr.substring(indexOfFunction).indexOf(' '));
  }

  @override
  String toString() {
    return 'LoggerStackTrace('
        'functionName: $functionName, '
        'callerFunctionName: $callerFunctionName, '
        'fileName: $fileName, '
        'lineNumber: $lineNumber, '
        'columnNumber: $columnNumber)';
  }
}
Run Code Online (Sandbox Code Playgroud)
print(LoggerStackTrace.from(StackTrace.current).toString());
Run Code Online (Sandbox Code Playgroud)


Lui*_*v99 7

我写了一个简单的类,它给出了当前函数和调用者函数,还有来自 StackTrace.current 属性的文件名、行号和列行。

代码如下:

class CustomTrace {
  final StackTrace _trace;

  String fileName;
  String functionName;
  String callerFunctionName;
  int lineNumber;
  int columnNumber;

  CustomTrace(this._trace) {
    _parseTrace();
  }

  String _getFunctionNameFromFrame(String frame) {
    /* Just giving another nickname to the frame */
    var currentTrace = frame;

    /* To get rid off the #number thing, get the index of the first whitespace */
    var indexOfWhiteSpace = currentTrace.indexOf(' ');

    /* Create a substring from the first whitespace index till the end of the string */
    var subStr = currentTrace.substring(indexOfWhiteSpace);

    /* Grab the function name using reg expr */
    var indexOfFunction = subStr.indexOf(RegExp(r'[A-Za-z0-9]'));

    /* Create a new substring from the function name index till the end of string */
    subStr = subStr.substring(indexOfFunction);

    indexOfWhiteSpace = subStr.indexOf(' ');

    /* Create a new substring from start to the first index of a whitespace. This substring gives us the function name */
    subStr = subStr.substring(0, indexOfWhiteSpace);

    return subStr;
  }

  void _parseTrace() {
    /* The trace comes with multiple lines of strings, (each line is also known as a frame), so split the trace's string by lines to get all the frames */
    var frames = this._trace.toString().split("\n");

    /* The first frame is the current function */
    this.functionName = _getFunctionNameFromFrame(frames[0]);

    /* The second frame is the caller function */
    this.callerFunctionName = _getFunctionNameFromFrame(frames[1]);

    /* The first frame has all the information we need */
    var traceString = frames[0];

    /* Search through the string and find the index of the file name by looking for the '.dart' regex */
    var indexOfFileName = traceString.indexOf(RegExp(r'[A-Za-z]+.dart'));

    var fileInfo = traceString.substring(indexOfFileName);

    var listOfInfos = fileInfo.split(":");

    /* Splitting fileInfo by the character ":" separates the file name, the line number and the column counter nicely.
      Example: main.dart:5:12
      To get the file name, we split with ":" and get the first index
      To get the line number, we would have to get the second index
      To get the column number, we would have to get the third index
    */

    this.fileName = listOfInfos[0];
    this.lineNumber = int.parse(listOfInfos[1]);
    var columnStr = listOfInfos[2];
    columnStr = columnStr.replaceFirst(")", "");
    this.columnNumber = int.parse(columnStr);
  }
}
Run Code Online (Sandbox Code Playgroud)

这个类接受一个 StackTrace 对象并读取它的字符串并解析它。

如何使用它(获取信息):

void main() {
  CustomTrace programInfo = CustomTrace(StackTrace.current);

  print("Source file: ${programInfo.fileName}, function: ${programInfo.functionName}, caller function: ${programInfo.callerFunctionName}, current line of code since the instanciation/creation of the custom trace object: ${programInfo.lineNumber}, even the column(yay!): ${programInfo.columnNumber}");
}
Run Code Online (Sandbox Code Playgroud)

变量programInfo现在有函数名、调用者函数名、行号、列号,甚至是当前程序执行的文件名。

您可以将以下内容打印到控制台:

print(StackTrace.current.toString());
Run Code Online (Sandbox Code Playgroud)

您将看到字符串的外观,并能够理解我如何解析字符串以获取信息。

这样做的简单好处是您不必安装任何库。我这样做是因为我正在使用 Dart 做一个项目,我不想在我的简单项目中添加/安装任何第三方库。并且您将通过调用构造函数最终得到一个包含所有信息的对象。这样做的缺点是,如果 Dart 出于某种原因在将来的某个地方更改了堆栈跟踪的字符串格式,这将不再起作用,但是如果发生这种情况,您可以轻松更改此类解析帧的方式*/

注意:此代码绝不是最优化的代码,但它有效:D。我希望看到一些更好的实现和抽象。


Gün*_*uer 5

import 'dart:mirrors';
...
MethodMirror methodMirror = reflect(functionOne).function;
Run Code Online (Sandbox Code Playgroud)

另见https://github.com/dart-lang/sdk/issues/11916#issuecomment-108381556

这仅适用于 Dart 命令行 VM,但不适用于浏览器或 Flutter,因为不支持反射。

https://pub.dartlang.org/packages/reflectable这样的代码生成解决方案可能会在反射不可用的情况下工作。

https://github.com/dart-lang/sdk/issues/28372似乎相关。


lrn*_*lrn 5

在Dart反射库中无法直接访问调用堆栈。

您可以获取堆栈跟踪的字符串表示形式,然后尝试对其进行解析:

var stack = StackTrace.current;
var stackString = "$stack"; // because the only method on StackTrace is toString.
Run Code Online (Sandbox Code Playgroud)

stack_trace软件包尝试使用多种已知的堆栈跟踪格式来为您执行此操作,因此也许:

import "package:stack_trace";
main() {
  print(Trace.current().frames[0].member);  // prints "main" unless minified.
}
Run Code Online (Sandbox Code Playgroud)

  • 它很可能很慢,是的。如果堆栈帧包可以进行延迟解析,那么您只解析第一帧,如果这就是您所需要的,它可能会更有效,但永远不会像直接访问堆栈那样有效。 (2认同)
  • 我试图在 Swift 中找到一个相当于 `#function` 文字表达式的 dart。这是合适的替代品吗?https://docs.swift.org/swift-book/ReferenceManual/Expressions.html (2认同)

Ale*_*nzi 5

LuisDev99 的答案不能很好地处理内部方法和匿名 lambda 块,因此我使用了更复杂的正则表达式方法。

我的解决方案:

/* 
  Define regex for each entry in the stack 

  group 0: full line
  group 1: stack index
  group 2: function name
  group 3: package
  group 4: file name
  group 5: line number
  group 6: column number

*/
RegExp regExp = new RegExp(r'^#(\d+) +(.+) +\(package:([^/]+)/(.+\.\w):(\d+):(\d+)\)$');

/* Get the stack as an array of strings */
var frames = StackTrace.current.toString().split("\n");

/* The second entry in the stack is the caller function */
var matches = regExp.allMatches(frames[1])

/* The regex matches each line of the stack only once so only one match */
var match = matches.elementAt(0);

/* Print all groups. Note that "groupCount" doesn't include group 0 (the whole line) */
for (int i = 0; i <= match.groupCount; i++) {
  print("group $i: " + match.group(i));
}
Run Code Online (Sandbox Code Playgroud)