I am trying to understand why the below code is not working as expected; the TypeDescriptor
is simply not picking up the custom converter from the attributes. I
We've also observed this behavior in pluggable systems involving loading assemblies from outside the appbase folder.
The root of all evil is a flaw in the TypeDescriptorAttribute
implementation.
The attribute has two constructor overloads, one for a plaintext type specification (which is — not unexpectedly — pure magic at runtime) and one for an early-bound typeof()
reference. If you use the second path, what could possibly go wrong? Well, actually the attribute only uses the first path. The real and correct runtime type reference is flattened into plaintext, and here there be dragons. So it's no use writing a typeof()
— it's always the plaintext-and-magic scenario inside.
The solution? No ideal one, but in our case we were consuming the type conversions within our system only, so we picked the ValueSerializerAttribute
instead. Which is basically the WPF's way of doing the same stuff. Its implementation is correct around the typeof()
.ctor
overload in that it succeeds in preserving the early-bound type identity and always loads the correct type, as written in code.
If you want system (or WinForms) code to use the type converter, this won't help.
I have seen cases, where I could not pickup attributes on internal fields from other assemblies. Not sure if it was a .NET bug or if it has been fixed.
The only thing I can thing of is that in the complex scenario, you may not have Reflection permission.
OK. Having spent pretty much an entire day trying to figure this out for Nullable type conversion.
txt.DataBindings.Add(nameof(txt.Text), this.Setting, propertyName); //fails
txt.DataBindings.Add(nameof(txt.Text), this.Setting, propertyName, false, DataSourceUpdateMode.OnValidation, null, format); //fails
txt.DataBindings.Add(nameof(txt.Text), this.Setting, propertyName, **true**, DataSourceUpdateMode.OnValidation, null, format); //WORKS
This is a little bit late, but this issue appeared when I asked for a TypeConverter that reside in another assembly which is not directly referenced by the executable assembly.
I had this problem as well and a workaround to the problem is to subscribe to the AssemblyResolve event of the current application domain and resolve the assembly manually.
This is far from a good solution, but it seems to work. I have no idea why the framework behaves this way. I would myself really want to find a less hackish way of resolving this problem.
public void DoMagic()
{
// NOTE: After this, you can use your typeconverter.
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
AppDomain domain = (AppDomain)sender;
foreach (Assembly asm in domain.GetAssemblies())
{
if (asm.FullName == args.Name)
{
return asm;
}
}
return null;
}
The answer to this other question should be applicable here. It is a much simpler solution than subscribing to AssemblyResolve
.
In summary, the idea is to set the TypeConverter
attribute using the full string name of the type converter class, rather than using typeof
to provide the class name.
In other words, instead of doing this:
[TypeConverterAttribute(typeof(TestConverter))]
public struct Test
{
...
}
do this:
[TypeConverterAttribute("MyTest.TestConverter")]
public struct Test
{
...
}