views:

1560

answers:

4

If I have the following code:

public class MyClass 
{ 
  public string myName { get; private set; } 
  public string myId { get; set; } 
}

A private compiler-generated variable is created for the setter. I want the setter not to be accessible for object initialization only. But, how do I get to initially set the myName variable?

Reading about object initialization I found the following:

... it’s read-only and the private field representing the underlying storage has a compiler-generated name that we cannot use in a constructor to assign to it. The solution is to use [...] object initializers

The solution would be, then, to use:

MyClass mc = new MyClass { 
myName = "What ever", 
myId = "1234" 
};

But this ends up in a compiler error sayin that:

The property or indexer 'MyClass.MyClass.myName' cannot be used in this context because the set accessor is inaccessible

So, is there a way to achieve setting this value using object initialization? If there is, what is the correct way to do it?

+8  A: 

No there is no way to achieve this. Object Initializers only allow you to access fields and properties which would be otherwise accessible outside the initializer.

Your best option is to use a constructor which explicitly sets these properties.

JaredPar
Thanks, I wanted to show students if this could be achieved using the new features of 3.0 but it seems the answer is no. Now I must file an errata for the book i got the quote from :P
jluna
+5  A: 

If they need to be set at initialisation then consider passing them as args to the constructor

David Archer
Yes, why make simple things complicated?
Ed Swangren
Because if you want to do something during object initialization, you do it in the constructor. It wouldn't make sense to do it anywhere else.
Matt Briggs
It is for academic purposes. I am showing students the new features of c# 3.0 and doing some tests with properties and object initializtion I got this question.The book (where I got the quote from) said it could be done but testing showed it couldn't so I decided to ask.
jluna
it can be done using reflection
David Archer
A: 

I've had this requirement int the past as well for OR/M stuff. What I basically do is use a real property with backer field and check to see if the property has already been set. If so, throw an exception.

public string myName
{
    get{ return _myName; }
    set
    {
     if( _myName != null && _myName != value )
      throw new Exception( "The myName property may only be set once." );
     _myName = value;
    }
}

private string _myName;

And another option for OR/M compatibility that also takes advantage of constructor initialization:

public class MyClass 
{ 
 [Obsolete( "For ORM use only!" )] 
 [EditorBrowsableState( EditorBrowsableState.Never )]
 public MyClass(){}

 public MyClass( string name ){ myName = name; }

 public string myName { get; private set; } 
 public string myId { get; set; } 
}
Paul Alexander
I would warn against this unless you have very clear conventions about this sort of thing established with everyone who will be using this code. If I see a property with a setter, I assume that I can use it to set a value, and it is going to REALLY irritate me if that throws an exception when I wasn't expecting it to.
Matt Briggs
Sure...but this makes sense for immutable fields like PK fields for an ORM.
Paul Alexander
Immutable fields that are only set once (i.e. initialized) can and should be initialized in constructor.
Pavel Minaev
@Pavel - yes they should, but many ORM tools require a parameterless constructor so you can't initialize in the constructor.
Paul Alexander
+2  A: 

Private set on myName means you can only initialize (set) it from something that is a member of MyClass. For example:

     public class MyClass {
  public string myName { get; private set; }
  public string myId { get; set; }

  public static MyClass GetSampleObject() {
   MyClass mc = new MyClass
   {
    myName = "Whatever",
    myId = "1234"
   };
   return mc;
  }
 }

(I copied and pasted your initialization code into the GetSampleObject method).

But if you try to set it outside MyClass, you get a compiler error, because private is private.

azheglov