First, a general note, what Xamarin calls their "linker" is actually more of a "dead code remover". It is supposed to prevent uncallable code from making it into the compiled app.
I have a type in my app. When I use reflection to get its constructors, I see zero constructors:
private static int GetConstructorCount(Type type) {
ConstructorInfo[] constructors = type.GetConstructors();
return constructors.Count();
}
Yet when I use reflection to see its instance members, I see many:
private static void LogMemberInfo(Type type) {
int constructorCount = GetConstructorCount(type);
MyLoggingMethod(constructorCount, "Constructors");
MemberInfo[] members = type.GetMembers();
List<string> willLog = new List<string>();
foreach(MemberInfo member in members) {
if (member.DeclaringType == type) {
willLog.Add(member.Name);
}
}
willLog.Sort();
foreach (string str in willLog) {
MyLoggingMethod.LogLine(str);
}
}
Output from the above is:
0 Constructors
lots of surviving members, including instance members
This is a problem, because the type is a gateway to a whole lot of other types. I was hoping that by getting rid of all the constructors, all the instance members would disappear. They don't.
Is this a bug in the linker? Or is there a reason why it might still not want to get rid of instance members?
I do access members of the type via casting. Perhaps this is the problem?
public class MySuperclass {
public static MySuperclass Instance {get; set;}
}
public MyClass: MySuperclass {
public static SomeMethod() {
MySuperclass object = MySuperclass.Instance;
MyClass castObject = object as MyClass; // castObject will always be null, as no constructors survived the linking process. But maybe the linker doesn't realize that?
if (castObject!=null) {
castObject.InstanceMethod();
}
}
}
UPDATE: Getting rid of all the casts did not solve the problem. I am calling virtual members of superclass objects in lots of places; that's my next guess, but if that's the problem, fixing will be messy.
At least in my case, calling any static method on a type leads to preservation of lots of instance members. I literally tried this:
Once the type was getting removed by the linker, I put in a call to MyType.DummyBool(). This led to a lot of instance members being preserved.
This may not be the case for everyone. But it was the case for me.
Another insidious thing to watch out for is that if a static class has any properties that are initialized on startup, and the class as a whole is preserved, then those properties are preserved, even if they are never called:
I am also seeing at least one case where code in a class that is removed by the linker nonetheless causes another class not to be removed. I assume this is a bug; however, my example is rather involved, and my attempts to get a simple repro have failed.