dotnet/wpf · error · InvalidOperationException

throw new…

Error message

throw new InvalidOperationException(SR.Format(SR.SpecialMethodMustBePublic, methodInfo.Name));

What it means

DependencyObjectPropertyDescriptor looks up ShouldSerialize*/ClearValue 'special methods' for a dependency property. If a matching method exists but is not public, it throws InvalidOperationException, because non-public special methods are deliberately unsupported (unlike the CLR TypeDescriptor, which does honor them).

Solutions

  1. Make the ShouldSerialize/ClearValue method public.
  2. Rename the method so it no longer matches the special-method naming pattern if it should not be used.
  3. Remove the method and rely on the dependency property's default serialization behavior.

Example fix

// before
internal bool ShouldSerializeWidth() => false;
// after
public bool ShouldSerializeWidth() => false;
Defensive patterns

Strategy: validation

Validate before calling

var m = type.GetMethod("ShouldSerialize" + propName,
    BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
if (m != null && !m.IsPublic)
    throw new InvalidOperationException($"{m.Name} must be public.");

Try / catch

try
{
    descriptor.ResetValue(component);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("must be public"))
{
    // fix accessibility or skip reset
}

Prevention

When it happens

Trigger: Declaring a non-public (internal/protected/private) ShouldSerialize<Property> or ClearValue helper method whose name matches a dependency property, then using the property through PropertyDescriptor APIs (e.g. PropertyGrid, serialization, ResetValue).

Common situations: Developers porting classic CLR property patterns (TypeDescriptor picks up non-public ShouldSerialize) to WPF dependency properties; refactoring that reduced method accessibility from public to internal.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/3fe4e461e593ace5. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/ComponentModel/DependencyObjectPropertyDescriptor.cs:634

            }

            string methodName = string.Concat(methodPrefix, _dp.Name);

            // According to spec, ShouldSerialize and Reset can be non-public.  So we should
            // assert ReflectionPermission here, like TypeDescriptor does.  But since every
            // assert is a security risk, we'll take the compatibility hit, and leave it out.

            MethodInfo methodInfo = reflectionType.GetMethod(methodName, flags, _dpBinder, types, null);

            if (methodInfo != null) 
            {
                // We don't support non-public ShouldSerialize/ClearValue methods.  We could just look
                // for public methods in the first place, but then authors might get confused as
                // to why their non-public method didn't get found, especially because the CLR
                // TypeDescriptor does find and use non-public methods.
                if( !methodInfo.IsPublic )
                {
                    throw new InvalidOperationException(SR.Format(SR.SpecialMethodMustBePublic, methodInfo.Name));
                }
            }

            return methodInfo;
}

        /// <summary>
        ///     This method is called on demand when we need to get at one or
        ///     more attributes for this property.  Because obtaining attributes
        ///     can be costly, we wait until now to do the job.
        /// </summary>
        private void MergeAttributes() 
        {
            AttributeCollection baseAttributes;

            if (_property != null) 
            {
                baseAttributes = _property.Attributes;

View on GitHub (pinned to 81131a70a4)