The actual root cause was your dll was getting loaded from different locations in the two different app domains. This causes .NET to think they are different assemblies which of course means the types are different (even though they have the same class name, namespace etc).
The reason Jeff's test failed when run through a unit test framework is because unit test frameworks generally create AppDomains with ShadowCopy set to "true". But your manually created AppDomain would default to ShadowCopy="false". This would cause the dlls to be loaded from different locations which leads to the nice "Object type cannot be converted to target type." error.
UPDATE: After further testing, it does seem to come down to the ApplicationBase being different between the two AppDomains. If they match, then the above scenario works. If they are different it doesn't (even though I've confirmed that the dll is loaded into both AppDomains from the same directory using windbg) Also, if I turn on ShadowCopy="true" in both of my AppDomains, then it fails with a different message: "System.InvalidCastException: Object must implement IConvertible".
UPDATE2: Further reading leads me to believe it is related to Load Contexts. When you use one of the "From" methods (Assembly.LoadFrom, or appDomain.CreateInstanceFromAndUnwrap), if the assembly is found in one of the normal load paths (the ApplicationBase or one of the probing paths) then is it loaded into the Default Load Context. If the assembly isn't found there, then it is loaded into the Load-From Context. So when both AppDomains have matching ApplicationBase's, then even though we use a "From" method, they are both loaded into their respective AppDomain's Default Load Context. But when the ApplicationBase's are different, then one AppDomain will have the assembly in its Default Load Context while the other has the assembly in it's Load-From Context.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…