7

I want to restrict creating object using default constructor. Because I have a desing like below:

class Program
{
    static void Main(string[] args)
    {
        BaseClass bc = new BaseClass("","");
        XmlSerializer xml = new XmlSerializer(typeof(BaseClass));
        StreamWriter sw = new StreamWriter(File.Create("c:\\test.txt"));
        xml.Serialize(sw,bc);
        sw.Flush();
        sw.Close();
    }
}
[Serializable]
public class BaseClass
{
    public string UserName, Password;
    // I don't want to create default constructor because of Authentication
    public BaseClass(string _UserName, string _Password)
    {
        UserName = _UserName;
        Password = _Password;
        f_Authenticate();
    }
    private void f_Authenticate() { }
}

public class DerivedClass:BaseClass
{
    public DerivedClass(string _UserName, string _Password) : base(_UserName, _Password)
    {
    }
}

This is ok. But when I make BaseClass to Serializable it'll generate this error: Unhandled Exception: System.InvalidOperationException: ConsoleApplication1.BaseC lass cannot be serialized because it does not have a parameterless constructor.

Now my design is collapsing because I need to have Username, Password parameters but default constructor is ruining my design....

What should I do?

uzay95
  • 16,052
  • 31
  • 116
  • 182
  • Actually I want to learn every possibilities. if I can/can't use what would you offer me? – uzay95 Apr 10 '12 at 12:01
  • Duplicate of http://stackoverflow.com/questions/267724/why-xml-serializable-class-need-a-parameterless-constructor – Matten Apr 10 '12 at 12:02

3 Answers3

12

Create a private default constructor

private DerivedClass()
{
    // code
}

The serialzer will successfully call this even though it's private

Robbie
  • 18,750
  • 4
  • 41
  • 45
  • No, because it requires a default constructor, thus it would be accessed publicly. – Tamara Wijsman Apr 10 '12 at 11:59
  • 1
    And to be completely thorough, you could add [Obsolete("Default constructor is only for serialization!", true)] to that private constructor, to ensure you don't accidentally call it from inside the class. – yoyo Oct 17 '13 at 21:42
  • This is true also for WinForms `UserControl` (s) created in the designer. Having a private constructor will still allow to use them in the toolbox. – ceztko Sep 24 '14 at 09:01
11

The class deserializing your instances requires a parameterless constructor to create the instance, but you don't have to implement a public constructor -- it's enough to have a private or internal constructor as long as it needs no parameters.

By the way, you can as well use the DataContractSerializer, which does not require a parameterless constructor and creates XML, too; it's always my primary choice :-)

Matten
  • 17,365
  • 2
  • 42
  • 64
  • I didn't realise this would be valid? I would of expected it to need a public constructor. Does this definitely work? If so, cool! – Liam Apr 10 '12 at 12:01
  • @TomWijsmanno, no, i meant by calling the non-default constructor (in OP's example), but i have removed my answer/comment as i realize that it is the serializer that calls the default constructor and hence it can't be private (i guess) – Robbie Apr 10 '12 at 12:03
  • @Robbie - actually it can. It *does* call the constructor even if it is private and it *surely* sets private fields with the serialized values, even if you don't have a setter for this attribute. – Matten Apr 10 '12 at 12:05
  • 1
    @Matten in that case i'm undeleting my answer, i was faster than you ;) – Robbie Apr 10 '12 at 12:08
1
  • Have you tried to create a private parameterless constructor?

  • If there is the need of a public one, you can always comment saying that it should not be used (not the best solution)

You also need to create properties in your Serializable class. Variables are not considered and will not be read or written during serialization/deserealization process

Luis Filipe
  • 8,488
  • 7
  • 48
  • 76