C
C#•3mo ago
hutoanhill

Storing types as strings

I need to store a Type as a string, then convert it back to a type. How do i do this? I've tried Type.Name then doing Type.GetType(typeName) but this returns null
17 Replies
Kouhai
Kouhai•3mo ago
You need the full type name Type.FullName
jcotton42
jcotton42•3mo ago
@hutonahill what for? Just out of curiosity.
hutoanhill
hutoanhillOP•3mo ago
I working on a system for saving configruable settings in a json. I need to save the datatype so i can pasre the user input into the right type for the new setting value
public abstract class SettingBase {
public string Description { get; set; }

public abstract Type getType();
}

public class Setting<T> : SettingBase {
public T Value { get; set; }

public override string ToString() {
return $"\t- {Description}\n" +
$"\t- Type: '{typeof(T)}' \n" +
$"\t- Value: '{Value}'";
}

public override Type getType() {
return typeof(T);
}

public Setting(string description, T value) {
Description = description;
Value = value;
}
}
public abstract class SettingBase {
public string Description { get; set; }

public abstract Type getType();
}

public class Setting<T> : SettingBase {
public T Value { get; set; }

public override string ToString() {
return $"\t- {Description}\n" +
$"\t- Type: '{typeof(T)}' \n" +
$"\t- Value: '{Value}'";
}

public override Type getType() {
return typeof(T);
}

public Setting(string description, T value) {
Description = description;
Value = value;
}
}
So parsing that to and from JSON
Kouhai
Kouhai•3mo ago
This might lead to some security risks 😅
hutoanhill
hutoanhillOP•3mo ago
very likely not doing anything super secure with it though this is the settings for a personal discord bot. what risks do you see though?
Kouhai
Kouhai•3mo ago
Well it depends on how you're loading the data back, because if you're creating an instance of any type you read then it's probably not secure
hutoanhill
hutoanhillOP•3mo ago
not sure what you mean... an instance of SettingBase?
Kouhai
Kouhai•3mo ago
No the actual type you're reading from the JSON file How are you loading the data from the JSON file?
hutoanhill
hutoanhillOP•3mo ago
i made an implimentation of JsonConverter
public class SettingBaseConverter : JsonConverter {

public override bool CanConvert(Type objectType) {
return typeof(SettingBase).IsAssignableFrom(objectType);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var settingBase = value as SettingBase;

Debug.Assert(settingBase != null, nameof(settingBase) + " != null");

writer.WriteStartObject();
writer.WritePropertyName("Description");
writer.WriteValue(settingBase.Description);
writer.WritePropertyName("Type");
writer.WriteValue(settingBase.getType().FullName);
writer.WritePropertyName("Value");
serializer.Serialize(writer, ((dynamic)settingBase).Value);
writer.WriteEndObject();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
JObject obj = JObject.Load(reader);

string description = obj["Description"].ToString();
string typeName = obj["Type"].ToString();
JToken valueToken = obj["Value"];

Type? type = Type.GetType(typeName);
if (type == null) {
throw new JsonException($"Unable to find the type: {typeName}");
}

Type settingType = typeof(Setting<>).MakeGenericType(type);
object value = valueToken.ToObject(type, serializer);

return Activator.CreateInstance(settingType, description, value);
}
}
public class SettingBaseConverter : JsonConverter {

public override bool CanConvert(Type objectType) {
return typeof(SettingBase).IsAssignableFrom(objectType);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
var settingBase = value as SettingBase;

Debug.Assert(settingBase != null, nameof(settingBase) + " != null");

writer.WriteStartObject();
writer.WritePropertyName("Description");
writer.WriteValue(settingBase.Description);
writer.WritePropertyName("Type");
writer.WriteValue(settingBase.getType().FullName);
writer.WritePropertyName("Value");
serializer.Serialize(writer, ((dynamic)settingBase).Value);
writer.WriteEndObject();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
JObject obj = JObject.Load(reader);

string description = obj["Description"].ToString();
string typeName = obj["Type"].ToString();
JToken valueToken = obj["Value"];

Type? type = Type.GetType(typeName);
if (type == null) {
throw new JsonException($"Unable to find the type: {typeName}");
}

Type settingType = typeof(Setting<>).MakeGenericType(type);
object value = valueToken.ToObject(type, serializer);

return Activator.CreateInstance(settingType, description, value);
}
}
Kouhai
Kouhai•3mo ago
I don't personally see any security problems here, but I'm no security expert But you're probably better off following what jcotton linked, although it's for STJ not Newtonsoft
Angius
Angius•3mo ago
Which is additional reason to go with it All that said, by the by, I find it interesting that configuration/settings would have no enforced shape Kinda hard to reason about it in the code, if the config file can be "whatever lmao"
hutoanhill
hutoanhillOP•3mo ago
no that's the great part. i can store values in any shape, i do have a data type that stores all these values, my config file has a List<SettingBase> and my bot allows you to manage all the values in that list. That's the whole point of this data structure: a settings file you can easily add and configure in the command line.
jcotton42
jcotton42•3mo ago
But what consumes those settings?
hutoanhill
hutoanhillOP•3mo ago
on start up i load them into an object and methods read the object then ive got a method to update the object and save its current state when i run the methods that let me modify the settings is taht what you mean?
The Fog from Human Resources
Newtonsoft.Json :wires:
hutoanhill
hutoanhillOP•3mo ago
looked into and implimented
Want results from more Discord servers?
Add your server