Struggling with generic class... design?

I have BaseClass that other classes will extend from:
c#
public class BaseClass {
public BaseClass() { /* Constructor */ }
public static T? JsonDeserialiseAs<T>(string json) where T : BaseClass { /* Do stuff */ }
}

public class MyClassA : BaseClass {
public string? SomeProp { get; set; } // Some properties that BaseClass doesn't have
public MyClassA() : base() { /* Constructor */ }
}
c#
public class BaseClass {
public BaseClass() { /* Constructor */ }
public static T? JsonDeserialiseAs<T>(string json) where T : BaseClass { /* Do stuff */ }
}

public class MyClassA : BaseClass {
public string? SomeProp { get; set; } // Some properties that BaseClass doesn't have
public MyClassA() : base() { /* Constructor */ }
}
The extending classes will have properties that BaseClass doesn't have, do knowing the type is important for deserialization. Instead of using MyClassA.JsonDeserialiseAs<MyClassA>(json) every time, I'd like to be able to use MyClassA.JsonDeserialize(json) What's the best way I can achieve this?
2 Replies
UnemployedNinja
UnemployedNinja8mo ago
My first thought was to make BaseClass a generic type, so I can have the following static method:
c#
public class BaseClass<T> where T : BaseClass<T> {
public BaseClass() { /* Constructor */ }

public static T? JsonDeserialize(string json) {
return JsonDeserialiseAs<T>(json);
}
}
c#
public class BaseClass<T> where T : BaseClass<T> {
public BaseClass() { /* Constructor */ }

public static T? JsonDeserialize(string json) {
return JsonDeserialiseAs<T>(json);
}
}
But this brings in two problems that I'd prefer to avoid: 1. I can't make a generic instance of BaseClass anymore and will always have to specify the type. 2. I always have to specify the type when checking if something is an instance of BaseClass. My next attempt was to make a typed version of BaseClass which the generic version will extend from, end then other classes from that:
c#
public class BaseClass { /* Holds all of the important constructors/properties etc */ }

public class BaseClass<T> : BaseClass where T : BaseClass<T> { // Only holds the type-dependant deserialization method.
public static T? JsonDeserialize(string json) {
return JsonDeserialiseAs<T>(json);
}
}

public class MyClassA : BaseClass<MyClassA> { }
c#
public class BaseClass { /* Holds all of the important constructors/properties etc */ }

public class BaseClass<T> : BaseClass where T : BaseClass<T> { // Only holds the type-dependant deserialization method.
public static T? JsonDeserialize(string json) {
return JsonDeserialiseAs<T>(json);
}
}

public class MyClassA : BaseClass<MyClassA> { }
Now I can access MyClassA.JsonDeserialize(json), however, MyClassA doesn't have access to all of the constructors from BaseClass. Meaning I'd have to duplicate, and rewrite them into BaseClass<T>, along with any annotations - dumb idea. I have a feeling the only way I can get what I want is by writing the JsonDeserialize method into every class that extends BaseClass In short, my aim is to somehow only have one declaration of the T JsonDeserialize method, without affecting how BaseClass is used/accessed and without having to rewrite the same method and annotations 50 times
MutableString
MutableString8mo ago
i'm not sure i understand exactly the issue is writing each time the whole thing public static DerivedClass DeserializeMe(string j) => JsonConverter.Deserialize<DerivedClass>(j); really harder than public static DerivedClass DeserializeMe(string j) => base.Deserialize<DerivedClass>(j); because in the end especially for static methods (which can't even be virtual) you have to write something also you can generate a constructor with quick actions/ctrl+. (or even not using them, if it's just data classes) you could try if bringing out deserialization from there in a separate architecture so that's not static anymore but then how would you call all this deserialization, a giant switch?
Want results from more Discord servers?
Add your server