36

OK, I know what you're thinking, "why write a method you do not want people to use?" Right?

Well, in short, I have a class that needs to be serialized to XML. In order for the XmlSerializer to do its magic, the class must have a default, empty constructor:

public class MyClass
{
  public MyClass()
  {
    // required for xml serialization
  }
}

So, I need to have it, but I don't want people to use it, so is there any attribute that can be use to mark the method as "DO NOT USE"?

I was thinking of using the Obsolete attribute (since this can stop the build), but that just seems kinda "wrong", is there any other way of doing this, or do I need to go ahead and bite the bullet? :)

Update

OK, I have accepted Keith's answer, since I guess in my heart of hearts, I totally agree. This is why I asked the question in the first place, I don't like the notion of having the Obsolete attribute.

However...

There is still a problem, while we are being notified in intellisense, ideally, we would like to break the build, so is there any way to do this? Perhaps create a custom attribute?

More focused question has been created here.

14 Answers 14

28

Prior to VS2013 you could use:

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]

so that it doesn't show up in IntelliSense. If the consumer still wants to use it they can, but it won't be as discoverable.

Keith's point about over-engineering still stands though.


Since VS2013 this feature has been removed. As noted in https://github.com/dotnet/roslyn/issues/37478 this was "by design" and apparently will not be brought back.

Sign up to request clarification or add additional context in comments.

Comments

17

If a class is [Serialisable] (i.e. it can be copied around the place as needed) the param-less constructor is needed to deserialise.

I'm guessing that you want to force your code's access to pass defaults for your properties to a parameterised constructor.

Basically you're saying that it's OK for the XmlSerializer to make a copy and then set properties, but you don't want your own code to.

To some extent I think this is over-designing.

Just add XML comments that detail what properties need initialising (and what to).

Don't use [Obsolete], because it isn't. Reserve that for genuinely deprecated methods.

1 Comment

It may need a param-less constructor, but (de)serializers shouldn't require it to be public.
17
throw new ISaidDoNotUseException();

3 Comments

I am torn between downvoting because this will break the deserializer and upvoting because of how much I laughed...
I laughed too! Hilarious :D
Who else actually tried to press Ctrl + . to see, if visual studio finds it in some library?
6

Nowadays you can use code analyzers for such need - thanks to Roslyn compiler in modern .NET.

Either you can write your own code analyzer. Here are some tips to start with:

Or use some already existing - this is way I have choosen for my needs:

Here is another nice "homepage" for Roslyn Analyzers: Cybermaxs/awesome-analyzers: A curated list of .NET Compiler Platform ("Roslyn") diagnostic analyzers and code fixes. Everyone can contribute here! https://github.com/Cybermaxs/awesome-analyzers

Comments

3

You could build your own Attribute derived class, say NonCallableAttribute to qualify methods, and then add to your build/CI code analysis task the check to monitor if any code is using those methods.

In my opinion, you really cannot force developers to not use the method, but you could detect when someone broke the rule as soon as possible and fix it.

3 Comments

Do you know a way, that once we create this attribute that you say, how? i don't know... to mark the method with stock line? like what obsolete do, but i don't wanna deny the user, just want to tell him there is a better option which also observe this property...
@deadManN Before VS2015, as far as I know there is no easy way to emulate the warning that Visual Studio shows for the Obsolete attribute for other custom attributes. That's why I suggested performing some analysis at build time, with a custom MSBuild script or any other program that can load your assemblies and perform a reflection based analysis. BUT specifically for Visual Studio 2015 and forward you might want to explore the new Roslyn Live Analyzers technology that lets you do exactly that: msdn.microsoft.com/en-us/magazine/dn879356.aspx
oh thanks, well i use 2015, BTW, i wish to know what would you do to tell the VS to warn people? and i'm not sure if i heard the word CI before, whats that... and how to add analysis task and what it's capable of... (if you can explain i'll be grateful)
3

I would actually be inclined to disagree with everyone that is advocating the use of the ObsoleteAttribute as the MSDN documentation says that:

Marking an element as obsolete informs the users that the element will be removed in future versions of the product.

Since the generic constructors for XML serialization should not be removed from the application I wouldn't apply it just in case a maintenance developer down the road is not familiar with how XML serialization works.

I have actually been using Keith's method of just noting that the constructor is used for serialization in XML documentation so that it shows up in Intellisense.

Comments

2

I read the heading and immediately thought "obsolete atribute". How about

    /// <summary>
    /// do not use
    /// </summary>
    /// <param name="item">don't pass it anything -- you shouldn't use it.</param>
    /// <returns>nothing - you shouldn't use it</returns>
    public bool Include(T item) { 
    ....

1 Comment

This won't raise a warning or message in the VS Error List or build output log though - that's why everyone uses [Obsolete] - because (at least before BannedApiAnalyzer was introduced) it was the only way to trigger a compiler message via an API usage/reference.
2

Separate your serializable object from your domain object.

1 Comment

Upvoted because it's a correct way to address the problem, but it's a pain in the foot.
0

Wow, that problem is bugging me too.

You also need default constructors for NHibernate, but I want to force people to NOT use C# 3.0 object initializers so that classes go through constructor code.

Comments

0

What you're looking for is the ObsoleteAttribute class:

using System;

public sealed class App {
   static void Main() {      
      // The line below causes the compiler to issue a warning:
      // 'App.SomeDeprecatedMethod()' is obsolete: 'Do not call this method.'
      SomeDeprecatedMethod();
   }

   // The method below is marked with the ObsoleteAttribute. 
   // Any code that attempts to call this method will get a warning.
   [Obsolete("Do not call this method.")]
   private static void SomeDeprecatedMethod() { }
}

2 Comments

I was going to create my own WarnOnUseAttribute derived from ObsoleteAttribute, to indicate that a method should not be called even though it is not "obsolete" (e.g. I wrote an extension method Buffered() that upgrades IEnumerable<T> to IReadOnlyList<T> and this method is wasteful if the argument already has type IReadOnlyList<T>, so I create a special overload with [WarnOnUse("...")] that takes IReadOnlyList<T>). This did not work because ObsoleteAttribute is sealed.
I disagree with the usage of Obsolete, as it typically means "will be removed in a later release.."
0

ObsoleteAttribute will probably work in your situation - you can even cause the build to break if that method is used.

Since obsolete warnings occur at compile time, and since the reflection needed for serialization occurs at runtime, marking that method obsolete won't break serialization, but will warn developers that the method is not there to be used.

Comments

0

I'm using the ObsoleteAttribute.

But also you can have some comments of course.

And finally remove it completely if you can (don't have to maintain the compatibility with something old). That's the best way.

Comments

0

There is already quite a lot of good answers. But I think the best option is to use serializer that can use parametrized constructor. It is not serializer you need but for example Entity Framework Core knows how to use parametrized constructors.

Entity Framework Core documentation:

If EF Core finds a parameterized constructor with parameter names and types that match those of mapped properties, then it will instead call the parameterized constructor with values for those properties and will not set each property explicitly.

Comments

0

Yep there is.

I wrote this blogpost about it Working with the designer.

And here is the code:

public class MyClass
{
    [Obsolete("reason", true)]
    public MyClass()
    {
        // required for xml serialization
    }
}

2 Comments

I just followed your link (only six short years after you posted it), and it's dead.
@WaiHaLee link has been updated (only 8 short years after you tried it).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.