3

Possible Duplicate:
Why XML-Serializable class need a parameterless constructor

Does anyone know if it is possible to prevent calling of a public constructor from outside a range of assemblies?

What I'm doing is coming up with a class library that has XML serializable classes. These classes make no sense if constructed without setting various properties so I want to prevent that state.

I'm wondering if there is a way to prevent anyone calling my public constructor, and keep it there only for serialization?

Community
  • 1
  • 1
Ian
  • 33,605
  • 26
  • 118
  • 198
  • Removed accessibility tag, not valid for this question. – Adrian Godong Jul 15 '09 at 11:27
  • 1
    Why do you want to keep a constructor public, when you want to prevent it from being called? – Narendra N Jul 15 '09 at 11:29
  • Is it required that the constructors be public, or could you make them internal? – Kenan E. K. Jul 15 '09 at 11:20
  • Apparently, they claim here they don't - http://stackoverflow.com/questions/267724/why-xml-serializable-class-need-a-parameterless-constructor – Kenan E. K. Jul 15 '09 at 11:28
  • Check this answer: [http://stackoverflow.com/questions/267724/why-xml-serializable-class-need-a-parameterless-constructor](http://stackoverflow.com/questions/267724/why-xml-serializable-class-need-a-parameterless-constructor). You may create internal or private constructor and still use XML serialization. – empi Jul 15 '09 at 11:26
  • I did not know that. I've always thought it had to be public, but I just tried it with an internal one, and it worked. – John Saunders Jul 15 '09 at 11:31
  • John. I'd be interested to know how you got that to work? All of my unit tests fail if I attempt to use anything but Public constructors. – Ian Jul 15 '09 at 11:36
  • I also tried it with private and it works. Could you post the exception? – empi Jul 15 '09 at 11:39
  • System.MissingMethodException: No parameterless constructor defined for this object.. – Ian Jul 15 '09 at 11:39
  • I just added a constructor, then tried it. I just realized I didn't try to deserialize. Hold five. – John Saunders Jul 15 '09 at 11:40
  • hmm, this may be a slightly different error though, because I use element = (T)Activator.CreateInstance(elementType) as part of my custom serialization... – Ian Jul 15 '09 at 11:40
  • try (T)Activator.CreateInstance(elementType, true) – empi Jul 15 '09 at 11:43
  • In XML Serialization? Odd. At any rate, deserialization works fine with the internal parameterless constructor. – John Saunders Jul 15 '09 at 11:44
  • ah. Thanks empi. Answered both my original, and the question I never asked but needed to know. :) – Ian Jul 15 '09 at 11:46
  • If your actual aim is to make it impossible to instantiate an object of your class except by calling certain constructors, [unfortunately that's impossible to ensure](http://msdn.microsoft.com/en-us/library/system.runtime.serialization.formatterservices.getuninitializedobject.aspx). – Daniel Earwicker Jul 15 '09 at 11:55
  • If you do not explicitly call any constructor in the base class, the parameterless constructor will be called implicitly. There's no way around it, you cannot instantiate a class without a constructor being called. – joe Jul 15 '09 at 11:21

3 Answers3

1

Typically, I would create a public constructor with parameters that will make the object valid and create a public parameterless constructor with valid default values.

public foo() {
  this.bar = -1;
}

public foo(int bar) {
  this.bar = bar;
}

Private/internal constructor can be used depending on your situation, and you can create a Factory pattern that deals with object creation for external code.

Adrian Godong
  • 8,802
  • 8
  • 40
  • 62
  • +1 just because I agree that normally you should initalize sensible values, however in this situation the values are other classes, which need to be correct. – Ian Jul 15 '09 at 11:47
0

To achieve what you are asking, you should probably make the constructor private, and then use a getInstance method to return the object if the correct assembly calls getInstance. You can do a check inside the getInstance method if you pass the object or assembly that called the function as one of its parameters.

AlbertoPL
  • 11,479
  • 5
  • 49
  • 73
0

I don't know if it would work in your case, but you could check the calling assembly:

if (Assembly.GetCallingAssembly().GetName().Name == "Forbidden.Assembly")
{
    throw new Exception(...);
}
Philippe Leybaert
  • 168,566
  • 31
  • 210
  • 223