I am using reflection (aka dart:mirrors) in dart. First: All the code seen here works perfectly in dartium (with dart native) but only partially when compiled with dart2js and run in chrome.

I have a class called BinaryReader than reads a class from a bytestream. Here is the code (stripped the repetitive part) that does so:

  void readObject(dynamic obj) {
    var inst = reflect(obj);
    inst.type.declarations.forEach((Symbol name, DeclarationMirror decl) {
      if(decl is VariableMirror) {
        var variable = decl;
        if(variable.metadata.length == 0) {
          return;
        }

        InstanceMirror attrib = variable.metadata.first;
        if(attrib.hasReflectee == false) {
          return;
        }

        if(attrib.reflectee is Field) {
          var field = attrib.reflectee as Field;
          var value;
          switch(field.type) {
            case I8: 
              value = getInt8();
              break;

            // ...

            case V3:
              value = new Vector3(getFloat(), getFloat(), getFloat());
              break;

            default:
              value = null;
              break;
          }

          if(value == null) {
            return;
          }

          inst.setField(name, value);
        }
      }
    });
  }

Importing mirrors is done the following way:

import 'model/M4SubMesh.dart';
import 'model/M4Model.dart';
import 'package:vector_math/vector_math.dart';
@MirrorsUsed(targets: const["M4SubMesh", "M4Model", "vector_math"], override: '*')
import 'dart:mirrors';

M4SubMesh and M4Model are the library names of the respective dart files. vector_math the one of vector_math.dart

At first i read an instance of M4Header which is part of M4Model library from the stream. All the values are correct, here what it looks like:

class M4Header
{
  @Field(UI32)
  int Signature;
  @Field(UI32)
  int Version;
  @Field(UI32)
  int numSubMeshes;
  @Field(UI32)
  int ofsSubMeshes;  
}

Then later i try to read a M4SubMeshHeader which looks like this:

class M4SubMeshHeader
{
  @Field(UI32)
  int gridX, gridY, gridZ;
  @Field(F32)
  num blockSize;
  @Field(V3)
  Vector3 bboxMin, bboxMax;
}

After reading, blockSize has a random value. bboxMin and bboxMax are null. What is going wrong here?

Greetings Cromon

有帮助吗?

解决方案

Found the solution! The annotation only applies to the first element in a declaration list. So the above example actually expanded to:

class M4SubMeshHeader
{
  @Field(UI32)
  int gridX;
  int gridY;
  int gridZ;
  @Field(F32)
  num blockSize;
  @Field(V3)
  Vector3 bboxMin;
  Vector3 bboxMax;
}

In my opinion this can be considered an error, ill have a look at the documentation and if its not mentioned there report it. So in the end blockSize became the value that should have been assigned gridY which made it look like random. But - to be honest - i also have to take some blame. 'bboxMin and bboxMax are null', this is wrong, bboxMin wasnt null, but had invalid values but as i left a line in the code where i used bboxMax before print-ing it i thought it allready broke at bboxMin.

Greetings Cromon

其他提示

I thinks there is a mismatch between the relection library and the language specification.

From language specification:

"Metadata can appear before a library, part header, class, typedef, type parameter, constructor, factory, function, field, parameter, or variable declaration and before an import, export or part directive".

That is, metadata can appear before variable declaration.

Now look at variable declaration definition.

variableDeclaration:
     declaredIdentifier (',' identifier)*
   ;
declaredIdentifier:
     metadata  finalConstVarOrType identifier

That is, variable declaration may consist from these parts:

  • Metadata, that applied to this declaration.
  • final/const/var/type specifier
  • List of identifiers in this declaration.

This means that one variable declaration can declare unlimited number of variables.

But it will still be one declaration, but not many different declarations in one declaration.

This only means that this variable declaration declares a set of variables.

Also, if metadata can appear before variable declaration it must be applied to all elements in this declaration.

This is because, as states language specification, metadata can appear only before declaration but not before some part in this declaration.

This is because, as states language specification, we have not THREE variable declarations but ONE variable declaration that declared THREE variables in this declaration.

var a, b, c;

So, if annotate this variable declaration.

@Foo var a, b, c;

Then, as states language specification, if metadata can apear before variable declaration then this metadata must be applied to whole declaration but not only to the first element in this declaration.

P.S.

This conclusions that can be made on the basis of this document:

https://www.dartlang.org/docs/spec/latest/dart-language-specification.html

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top