mardi 23 juin 2020

C# How to init property (without setter) by reflection

Task: Serialize a list of objects into a byte[] using protobuf.

Without reflection all is good

.proto

message MyObject{
  int32 id = 1;
  int32 value = 2;
}

message MyObjects {
  repeated MyObject objects = 1;
}

.cs

public static byte[] ToByteArray(List<MyObject> obj) {
    var objects = new MyObjects {
        Objects = {obj}
    };
    return objects.ToByteArray();
} 

Since I need to serialize many different types in this way, I want to write a universal method using reflection.

Problem: Protobuf itself generates entities and properties for them, but it does not create a setter for RepeatedField, which means that I can not set the value using GetProperty("Objects")?.SetValue(objects, obj). System.ArgumentException: Set Method not found for 'Objects'

.cs (protobuf generated)

public pbc::RepeatedField<global::Test.MyObject> Objects {
  get { return objects_; }
}

.cs

public static byte[] ToByteArray<T, E>(List<T> obj) where T : IMessage where E : IMessage {
    var objects = Activator.CreateInstance<E>();
    objects.GetType().GetProperty("Objects")?.SetValue(objects, obj);
    return objects.ToByteArray();
} 

Question: How to use reflection to set values ​​for a property during object creation, just as I do it without reflection?

How to write this "new MyObjects {Objects = {obj}}; (where obj: IEnumerable)" using reflection

Various conclusions:

  • I noticed that filling properties that do not have a setter is only possible for collections and only when creating an object.
  • Most likely I need an alternative way to instantiate the class. Activator.CreateInstance() is not fulfilling my task.




Aucun commentaire:

Enregistrer un commentaire