我正在为我的winform程序进行控制,并且在保存测试表单时会发生此错误。
这是解决方案结构,控件库在1个项目中分离,另一个是包含测试表单的测试项目。
Solution
├ Test (Test Project)
│ └ Form1
└ WinFormControls (Library Project)
└ ImageButton (UserControl)
该控件附有TypeConverter
,这里是简要代码。
为了简化这个问题,我省略了其他方法,你可以从this link读取它
public class StateConverter : ExpandableObjectConverter
{
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if(destinationType == typeof(InstanceDescriptor))
{
var ctor = typeof(State).GetConstructor(new Type[] { typeof(int), typeof(Image) });
if (ctor != null)
{
var state = (State)value;
return new InstanceDescriptor(ctor, new object[] { state.GetData(), state.Image });
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
这里不总是发生错误是重现的步骤:
经过一些调试后,我发现此行发生错误:
var state = (State)value;
起初我猜测值为null,所以我添加了一些日志:
try {
var state = (State)value;
} catch (Exception ex) {
File.AppendAllText("errorlog.txt", ex.ToString() +
(value == null ? "NULL" : value.GetType().ToString());
}
最后我得到了:
System.InvalidCastException:指定的强制转换无效。在WinFormControls.ImageButton.StateConverter.ConvertTo ...... WinFormControls.ImageButton + State
所以值不是null,值的类型正是我所投射的。
更新
输出AssemblyQualifiedName,IsAssignableFrom,是:
value.GetType().AssemblyQualifiedName;
typeof(State).AssemblyQualifiedName;
typeof(State).IsAssignableFrom(value.GetType());
value.GetType().IsAssignableFrom(typeof(State))
value is State
ReferenceEquals(value.GetType(), typeof(State))
奇怪的结果:
WinFormControls.ImageButton + State,WinFormControls,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null WinFormControls.ImageButton + State,WinFormControls,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null 假 假 假 假
两个问题:
这是因为类型转换器和设计器加载类型的方式不同。类型转换器使用CLR缓存来加载类型,而设计器使用类型解析服务。因此,当您更改类库项目并再次构建它时,CLR从CLR中的类型的先前缓存版本加载程序集,而设计器从新构建的程序集加载它并导致类型不匹配。
要解决这个问题,在类库项目中:
AssemblyInfo.CS
并更改程序集版本属性以更改每个构建中程序集的内部版本号并保存文件。这会强制CLR使其缓存无效并从新版本的程序集加载新类型:
[assembly: AssemblyVersion("1.0.0.*")]
<Deterministic>false</Deterministic>
这个问题已经解决了in this forum post。