{"record":{"id":"3fe4e461e593ace5","repo":"dotnet/wpf","slug":"throw-new-invalidoperationexception-sr-format-sr-3fe4e4","errorCode":null,"errorMessage":"throw new InvalidOperationException(SR.Format(SR.SpecialMethodMustBePublic, methodInfo.Name));","messagePattern":"throw new InvalidOperationException\\(SR\\.Format\\(SR\\.SpecialMethodMustBePublic, methodInfo\\.Name\\)\\);","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/ComponentModel/DependencyObjectPropertyDescriptor.cs","lineNumber":634,"sourceCode":"            }\n\n            string methodName = string.Concat(methodPrefix, _dp.Name);\n\n            // According to spec, ShouldSerialize and Reset can be non-public.  So we should\n            // assert ReflectionPermission here, like TypeDescriptor does.  But since every\n            // assert is a security risk, we'll take the compatibility hit, and leave it out.\n\n            MethodInfo methodInfo = reflectionType.GetMethod(methodName, flags, _dpBinder, types, null);\n\n            if (methodInfo != null) \n            {\n                // We don't support non-public ShouldSerialize/ClearValue methods.  We could just look\n                // for public methods in the first place, but then authors might get confused as\n                // to why their non-public method didn't get found, especially because the CLR\n                // TypeDescriptor does find and use non-public methods.\n                if( !methodInfo.IsPublic )\n                {\n                    throw new InvalidOperationException(SR.Format(SR.SpecialMethodMustBePublic, methodInfo.Name));\n                }\n            }\n\n            return methodInfo;\n}\n\n        /// <summary>\n        ///     This method is called on demand when we need to get at one or\n        ///     more attributes for this property.  Because obtaining attributes\n        ///     can be costly, we wait until now to do the job.\n        /// </summary>\n        private void MergeAttributes() \n        {\n            AttributeCollection baseAttributes;\n\n            if (_property != null) \n            {\n                baseAttributes = _property.Attributes;","sourceCodeStart":616,"sourceCodeEnd":652,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/ComponentModel/DependencyObjectPropertyDescriptor.cs#L616-L652","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","solutions":["Make the ShouldSerialize/ClearValue method public.","Rename the method so it no longer matches the special-method naming pattern if it should not be used.","Remove the method and rely on the dependency property's default serialization behavior."],"exampleFix":"// before\ninternal bool ShouldSerializeWidth() => false;\n// after\npublic bool ShouldSerializeWidth() => false;","handlingStrategy":"validation","validationCode":"var m = type.GetMethod(\"ShouldSerialize\" + propName,\n    BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);\nif (m != null && !m.IsPublic)\n    throw new InvalidOperationException($\"{m.Name} must be public.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    descriptor.ResetValue(component);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"must be public\"))\n{\n    // fix accessibility or skip reset\n}","preventionTips":["Declare ShouldSerialize*/ClearValue helpers as public.","Remember WPF's DependencyObjectPropertyDescriptor is stricter than CLR TypeDescriptor regarding accessibility.","Add a unit test that reflects over special methods and asserts IsPublic."],"tags":["wpf","propertydescriptor","accessibility","invalid-operation"],"backgroundTag":"invalid-argument-value","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}