好的,由于 Vikas 对问题的清晰界定,我最终完成了我自己问题的答案。解决方案是针对此类问题的标准 PCL 方法:创建接口、配置容器、使用 DI。
在这种情况下,在我的 PCL中,我创建了一个 INewtonsoftJsonSettingsProvider 接口,该接口具有我用作属性的两个设置,如下所示:
public interface INewtonsoftJsonSettingsProvider
{
JsonSerializerSettings Default { get; set; }
JsonSerializerSettings Concrete { get; set; }
}
然后,在我的 PCL中,我创建了这个类的具体实现,如下所示:
public class NewtonsoftJsonSettingsProvider : Interfaces.INewtonsoftJsonSettingsProvider
{
public JsonSerializerSettings Default { get; set; }
public JsonSerializerSettings Concrete { get; set; }
}
注意:我可以很容易地跳过接口,只使用这个帮助类,但我喜欢在处理容器时使用接口。
然后,在我的 Newtonsoft 序列化程序所在的 PCL中,我使用容器中的设置,而不是直接在序列化方法内部创建这些设置。我将继续在此处包含该代码(由于这个问题,我将序列化抽象为接口,因此我可以换出实现):
public class NewtonsoftJsonSerializer : ICustomSerializer
{
public static void RegisterAsSerializerInContainer()
{
var key = Resx.DIKeys.DefaultSerializer;
var typeContract = typeof(ICustomSerializer);
if (DI.Ton.KeyExists(key))
{
var instance = DI.Ton.Get(typeContract, key);
DI.Ton.RemoveInstance(key, instance, typeContract);
}
DI.Ton.AddImplementationType(typeof(ICustomSerializer),
typeof(NewtonsoftJsonSerializer),
isShared: true);
var serializer = new NewtonsoftJsonSerializer();
DI.Ton.AddInstance<ICustomSerializer>(Resx.DIKeys.DefaultSerializer, serializer);
}
/// <summary>
/// This is used to overcome the problem of PCL vs non-PCL versions when using TypeNameAssemblyFormat.
/// see http://stackoverflow.com/questions/27080363/missingmethodexception-with-newtonsoft-json-when-using-typenameassemblyformat-wi
/// </summary>
/// <returns></returns>
private static INewtonsoftJsonSettingsProvider GetSettingsProvider()
{
var key = typeof(INewtonsoftJsonSettingsProvider).Name;
var settings = DI.Ton.GetInstance<INewtonsoftJsonSettingsProvider>(key);
return settings;
}
public byte[] SerializeToBytes(object obj)
{
var settings = GetSettingsProvider();
var json = JsonConvert.SerializeObject(obj, settings.Default);
var jsonBytes = Encoding.UTF8.GetBytes(json);
return jsonBytes;
}
public T DeserializeFromBytes<T>(byte[] serializedBytes)
{
var json = Encoding.UTF8.GetString(serializedBytes, 0, serializedBytes.Length);
var settings = GetSettingsProvider();
var obj = JsonConvert.DeserializeObject<T>(json, settings.Default);
return obj;
}
public byte[] SerializeToBytes_UseConcreteTypes(object obj)
{
var settings = GetSettingsProvider();
var json = JsonConvert.SerializeObject(obj, settings.Concrete);
var jsonBytes = Encoding.UTF8.GetBytes(json);
return jsonBytes;
}
public T DeserializeFromBytes_UseConcreteTypes<T>(byte[] serializedBytes)
{
var json = Encoding.UTF8.GetString(serializedBytes, 0, serializedBytes.Length);
var settings = GetSettingsProvider();
var obj = JsonConvert.DeserializeObject<T>(json, settings.Concrete);
return obj;
}
}
然后,在我使用的非 PCL 和非 XamarinSystem.Runtime.Serialization.Formatters.FormatterAssemblyStyle
中(可能在 PCL 中工作,但 Xamarin 有问题 - 见下文),我按照 Vikas 的回答中的解释正确配置了容器:
private static void UseNewtonsoft()
{
var defaultNewtonsoftSettings = new Newtonsoft.Json.JsonSerializerSettings()
{
Formatting = Newtonsoft.Json.Formatting.Indented
};
var concreteNewtonsoftSettings = new Newtonsoft.Json.JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
Formatting = Formatting.Indented,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full
};
Serialization.NewtonsoftJsonSettingsProvider.CreateAndRegisterWithContainerIdem(defaultNewtonsoftSettings, concreteNewtonsoftSettings);
Serialization.NewtonsoftJsonSerializer.RegisterAsSerializerInContainer();
}
这在我的 .Net 测试项目中执行没有问题。但是,当我在 Xamarin.Android 项目中使用它时,我收到一条错误消息,指出 Newtonsoft 和 MonoAndroid mscorlib 中都存在 FormatterAssemblyStyle。由于 Xamarin Studio 似乎没有做外部别名,我使用反射和动态如下:
void UseNewtonsoft()
{
var defaultNewtonsoftSettings = new Newtonsoft.Json.JsonSerializerSettings()
{
Formatting = Newtonsoft.Json.Formatting.Indented
};
//hack: FormatterAssemblyStyle exists in two dlls and extern alias doesn't work in xamarin studio
var assmNewtonsoft = System.Reflection.Assembly.GetAssembly(typeof(Newtonsoft.Json.ConstructorHandling));
var enumType = assmNewtonsoft.GetType("System.Runtime.Serialization.Formatters.FormatterAssemblyStyle");
dynamic enumInstance = Enum.Parse(enumType, "Full");
var concreteNewtonsoftSettings = new Newtonsoft.Json.JsonSerializerSettings()
{
TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Objects,
Formatting = Newtonsoft.Json.Formatting.Indented,
//TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Full //set using dynamic
};
dynamic dynSettings = concreteNewtonsoftSettings;
dynSettings.TypeNameAssemblyFormat = enumInstance;
commonGib.Serialization.NewtonsoftJsonSettingsProvider.CreateAndRegisterWithContainerIdem(defaultNewtonsoftSettings, concreteNewtonsoftSettings);
commonGib.Serialization.NewtonsoftJsonSerializer.RegisterAsSerializerInContainer();
}