Mac版VS 2017社区版Xamarin.iOS开发模型字段丢失问题求助
问题原因与解决方案
这个问题是Xamarin.iOS链接器(Linker)的优化行为导致的,具体来拆解下:
为什么会出现这种奇怪的现象?
Xamarin.iOS的链接器会自动移除它判定为“未被使用”的代码,以此来减小最终应用的体积。而你用来序列化的Json.NET是通过反射来读取类属性的——但链接器无法识别反射调用的依赖关系,所以如果你的iOS项目代码里没有直接访问SearchRequest的某个属性(比如FullName),链接器会认为这个属性的get/set方法是无用的,直接把它们从编译后的代码里移除了。
这就完美解释了你遇到的所有情况:
- 当你没在iOS项目里访问
FullName时,PCL里序列化出来的对象只有EmailAddress(因为你访问过它),甚至是空对象{}; - 当你添加
Console.WriteLine(searchRequest.FullName)后,链接器看到这个属性被直接引用了,就会保留它的访问器,Json.NET就能正常序列化所有属性; - 哪怕你在
await client.Search(...)之后访问属性,链接器在编译阶段就已经决定了要保留哪些成员,所以同样能让序列化正常工作。
如何解决这个问题?
有几种可靠的方法可以避免链接器误删模型类的属性:
1. 使用[Preserve]特性标记模型类
这是最推荐的方法,直接告诉链接器保留类的所有成员。你需要先引入Foundation命名空间,然后在类或属性上添加特性:
using Foundation; // 标记整个类,保留所有成员 [Preserve(AllMembers = true)] public class SearchRequest { public string FullName {get; set;} public string EmailAddress {get;set;} }
或者单独标记每个属性:
using Foundation; public class SearchRequest { [Preserve] public string FullName {get; set;} [Preserve] public string EmailAddress {get;set;} }
2. 修改链接器行为
在iOS项目的属性设置里调整链接器的优化范围:
- 右键你的Xamarin.iOS项目 → 属性 → iOS Build
- 在“链接器行为”(Linker Behavior)下拉菜单中选择仅链接SDK程序集(Link SDK assemblies only)
- 这样链接器只会优化系统SDK的代码,不会碰你自己写的PCL模型类,缺点是应用体积会稍微大一点。
3. 添加“占位”代码强制保留属性
如果你不想用特性或修改链接器设置,可以在模型类里加一个空方法,里面访问所有属性,让链接器认为这些属性被使用了:
public class SearchRequest { public string FullName {get; set;} public string EmailAddress {get;set;} // 链接器会认为这些属性被引用,不会移除 public void PreserveMembers() { var _ = FullName; var __ = EmailAddress; } }
然后在iOS项目里调用这个方法:
SearchRequest searchRequest = new SearchRequest { EmailAddress = "sample@domain.com", FullName = "Sample Full Name" }; searchRequest.PreserveMembers(); // 调用后链接器会保留所有属性 var result = await client.Search(searchRequest);
4. 配合Json.NET的JsonProperty特性
虽然单独用JsonProperty不一定能阻止链接器,但结合Preserve特性会更稳妥,同时明确指定序列化的字段名:
using Foundation; using Newtonsoft.Json; [Preserve(AllMembers = true)] public class SearchRequest { [JsonProperty("FullName")] public string FullName {get; set;} [JsonProperty("EmailAddress")] public string EmailAddress {get;set;} }
验证问题根源
你可以检查当前项目的链接器设置:如果是链接所有程序集(Link all assemblies),那大概率就是这个问题导致的。Debug模式下默认可能是“不链接”或“仅链接SDK”,所以有时候不会出现,但Release模式下默认是“链接所有程序集”,很容易触发这个问题。
内容的提问来源于stack exchange,提问作者Moamen Naanou
相关产品推荐
相关产品推荐

