Чтобы сделать вашу функцию более переносимой, используйте ее как таковой:
os.path.join(os.sep, 'home', 'build', 'test', 'sandboxes', todaystr, 'new_sandbox')
или
os.path.join(os.environ.get("HOME"), 'test', 'sandboxes', todaystr, 'new_sandbox')
Вы можете принять и расширить общий подход с этого ответа до Десериализацию полиморфных классов json без информации о типах, используя json.net или этот ответ - Как вызвать JsonConvert.DeserializeObject и отключить JsonConverter, примененный к базовому типу через [JsonConverter]? , создав пользовательский JsonConverter
для List<IMachineInfo>
, который выполняет следующее:
JToken
. Для этого сначала представьте общий конвертер базового класса следующим образом:
public abstract class JsonListItemTypeInferringConverterBase<TItem> : JsonConverter
{
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
protected abstract bool TryInferItemType(Type objectType, JToken json, out Type type);
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Get contract information
var contract = serializer.ContractResolver.ResolveContract(objectType) as JsonArrayContract;
if (contract == null || contract.IsMultidimensionalArray || objectType.IsArray)
throw new JsonSerializationException(string.Format("Invalid array contract for {0}", objectType));
if (reader.MoveToContent().TokenType == JsonToken.Null)
return null;
if (reader.TokenType != JsonToken.StartArray)
throw new JsonSerializationException(string.Format("Expected {0}, encountered {1} at path {2}", JsonToken.StartArray, reader.TokenType, reader.Path));
var collection = existingValue as IList<TItem> ?? (IList<TItem>)contract.DefaultCreator();
// Process the collection items
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.EndArray:
return collection;
case JsonToken.Comment:
break;
default:
{
var token = JToken.Load(reader);
Type itemType;
if (!TryInferItemType(typeof(TItem), token, out itemType))
break;
collection.Add((TItem)serializer.Deserialize(token.CreateReader(), itemType));
}
break;
}
}
// Should not come here.
throw new JsonSerializationException("Unclosed array at path: " + reader.Path);
}
public override bool CanConvert(Type objectType)
{
return objectType.IsAssignableFrom(typeof(List<TItem>));
}
}
public static partial class JsonExtensions
{
public static JsonReader MoveToContent(this JsonReader reader)
{
while ((reader.TokenType == JsonToken.Comment || reader.TokenType == JsonToken.None) && reader.Read())
;
return reader;
}
}
Затем создайте конкретную версию, которая десериализует только записи списка типа Machine1
следующим образом: [1137 ]
public class Machine1ListConverter<TMachineInfo> : JsonListItemTypeInferringConverterBase<TMachineInfo> where TMachineInfo : IMachineInfo
{
protected override bool TryInferItemType(Type objectType, JToken json, out Type type)
{
var obj = json as JObject;
if (obj != null && obj.GetValue("powerWatts", StringComparison.OrdinalIgnoreCase) != null)
{
type = typeof(Machine1);
return true;
}
type = null;
return false;
}
}
И, наконец, десериализовать вашу строку JSON следующим образом:
var settings = new JsonSerializerSettings
{
Converters = { new Machine1ListConverter<IMachineInfo>() },
};
var list = JsonConvert.DeserializeObject<List<IMachineInfo>>(jsonString, settings);
Если вы хотите десериализовать в конкретный List<Machine1>
, сделайте:
var settings = new JsonSerializerSettings
{
Converters = { new Machine1ListConverter<Machine1>() },
};
var list = JsonConvert.DeserializeObject<List<Machine1>>(jsonString, settings);
Примечания:
Преобразователь необходимо применять ко всей коллекции вместо элементов коллекции, поскольку JsonConverter.ReadJson
не имеет возможности пропускать токен, читаемый в данный момент, и предотвращать его возвращаемое значение после добавления в содержащий объект.
Для десериализации только элементов типа Machine2
вы можете аналогичным образом создать Machine2ListConverter
, в котором TryInferItemType()
проверяет наличие dbm
.
Для десериализации вы звоните
JsonConvert.DeserializeObject<List<Machine1>>(@"C/Path/jsonfile", settings);
Но JsonConvert.DeserializeObject Method (String, JsonSerializerSettings)
десериализует строку JSON, а не именованный файл. Для десериализации из файла см. Десериализацию JSON из файла .
Демонстрационная скрипка здесь .