34

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.

Community
  • 1
  • 1
Rob Cooper
  • 28,567
  • 26
  • 103
  • 142

14 Answers14

27

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.

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81
ICR
  • 13,896
  • 4
  • 50
  • 78
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.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Keith
  • 150,284
  • 78
  • 298
  • 434
  • It may need a param-less constructor, but (de)serializers shouldn't require it to be public. – JJJ May 23 '18 at 08:19
11
throw new ISaidDoNotUseException();
FlySwat
  • 172,459
  • 74
  • 246
  • 311
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.

Community
  • 1
  • 1
rjzii
  • 14,236
  • 12
  • 79
  • 119
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.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Sergio Acosta
  • 11,418
  • 12
  • 62
  • 91
  • 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... – Hassan Faghihi Oct 18 '15 at 13:24
  • 2
    @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: https://msdn.microsoft.com/en-us/magazine/dn879356.aspx – Sergio Acosta Oct 19 '15 at 17:37
  • 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) – Hassan Faghihi Oct 20 '15 at 05:49
3

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

Saly
  • 51
  • 4
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) { 
    ....
hometoast
  • 11,522
  • 5
  • 41
  • 58
1

Separate your serializable object from your domain object.

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.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Sir Rippov the Maple
  • 7,491
  • 5
  • 42
  • 52
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() { }
}
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Mark Ingram
  • 71,849
  • 51
  • 176
  • 230
  • 1
    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` to `IReadOnlyList` and this method is wasteful if the argument already has type `IReadOnlyList`, so I create a special overload with `[WarnOnUse("...")]` that takes `IReadOnlyList`). This did not work because `ObsoleteAttribute` is `sealed`. – Qwertie May 22 '14 at 20:39
  • I disagree with the usage of Obsolete, as it typically means "will be removed in a later release.." – Jim Aho Jan 23 '17 at 12:05
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
    }
}
phooBarred
  • 73
  • 7
chrissie1
  • 5,014
  • 3
  • 26
  • 26
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.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Biri
  • 7,101
  • 7
  • 38
  • 52
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.

Jon Limjap
  • 94,284
  • 15
  • 101
  • 152
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.

Lukáš Kmoch
  • 1,239
  • 11
  • 11