ค้นหาเว็บไซต์

c# - วิธีการใช้งาน polymorphism อย่างถูกต้องกับ protobuf.js และ reflection


สมมติว่าฉันมีลำดับชั้นของคลาสที่ถูกใช้งานใน c# กับ Protobuf.net (นอกจากนี้ยังจะมีคลาส Rectangle ซึ่งใช้งาน Shape แต่ฉันละเว้นไว้เพื่อความกระชับ)

[ProtoContract]
[ProtoInclude(1, typeof(Circle))]
public class Shape {
}

[ProtoContract]
public class Circle : Shape {

    [ProtoMember(1)]
    public int Radius {get;set;}
}

ฉันต้องการแสดงลำดับชั้นคลาสนี้เดียวกันใน TypeScript โดยใช้ protobuf.js อย่างไรก็ตาม ดูเหมือนไม่สามารถหาวิธีแม็ปฟิลด์ 'oneof' กลับไปยังซับคลาสได้

นี่คือสิ่งที่ดีที่สุดที่ฉันสามารถคิดออกมาได้:

// It's not possible to make this inherit from 'Shape'
class Circle extends Message<Circle> {
  @Field.d(1, "int32")
  radius: number;
}

class Shape extends Message<Shape> implements IShape {
  @Field.d(1, Circle)
  circle: Circle;

  @OneOf.d("circle") // ,"rectangle"
  which: string;

  // Implements the property on ICircle
  get radius(): number {
    return this.circle.radius;
  }
}

interface IShape {
}

interface ICircle extends IShape {
  radius: number;
}

function isCircle(shape: IShape): shape is ICircle {
  return (shape as any).which === "circle";
}

const shape = new Shape({
  circle: new Circle({ radius: 5 }),
  which: "circle"
});

const buffer = Shape.encode(shape).finish();
const decoded = Shape.decode(buffer);

if (isCircle(decoded)) {
  const itsACircle: ICircle = decoded;
  // Do something
}

นี่รู้สึกเหมือนงานโกงสำหรับฉัน เพราะว่า:

  1. เราต้องเปิดเผยฟิลด์ย่อยทั้งหมดที่เป็นไปได้เป็นคุณสมบัติในคลาสฐาน Shape (ในกรณีนี้คือคุณสมบัติ radius ของ Circle)
  2. ไม่มีคลาสใดที่นำ ICircle ไปใช้งานจริง ดังนั้นถ้าเราล้มเหลวในการเปิดเผยคุณสมบัติบางอย่างอย่างถูกต้อง คอมไพเลอร์จะไม่เตือนเรา
  3. การป้องกันประเภทพึ่งพาการแปลงชนิดเป็น any.

ใครสามารถแนะนำวิธีที่ดีกว่าในการทำสิ่งนี้ได้บ้าง?