views:

236

answers:

5

What would be the best way to implement the following?

I have a collection of objects that implement an interface, internally I want to be able to expose set and get on the properties and externally only get.

Here's an example of the sort of thing I want... That does't compile.

public interface ITable
{
   string Name { get; }
}

internal interface IInternalTable 
{
   string Name { get; set; }
}

internal class Table : ITable, IInternalTable
{
   public string Name { get; set; }
   public string ITable.Name { get { return Name; } }
}

public class Database
{
    private List<IInternalTable> tables;

    public List<ITable>
    {
       get { return this.tables; }
    }
}
+3  A: 

Use this:

public interface ITable
{
    string Name { get; }
}

public class Table : ITable
{
    public string Name { get; internal set; }
}

public class Database
{
    public List<ITable> Tables { get; private set; }
}

Note: The accessibility modifier used on a get or set accessor can only restrict visibility not increase it.

Koistya Navin
That won't help if the code accessing "Name" is in the same assembly, since "internal" is like "public" within an assembly.
scraimer
@scraimer: That's what the OP wants: "internally [...]set and get [...] externally only get."
Richard
@Richard... hmm, I guess I misunderstood "internally" not as the "internal" keyword, but as "internally to the class Database".
scraimer
+1  A: 

If Table implements IInternalTable implicitly, and IInternalTable is internal, then those methods will only be accessible internally (because only internal code will be able to use IInternalTable:

public interface ITable
{
   string Name { get; }
}

internal interface IInternalTable 
{
   string Name { get; set; }
}

public class Table : ITable, IInternalTable
{
   public string Name { get; set; }
   string ITable.Name { get { return Name; } }
}

public class Database
{
    private List<Table> tables;

    public List<Table> Tables
    {
       get { return this.tables; }
    }
}

(Also now exposing Table type to avoid issues with lack of covariance... which could also be solved by Database.Tables returning a copy and having a different internal only property.)

Richard
A: 

It won't compile because there is no conversion between IInternalTable and ITable. Solution is like Koistya Navin suggested:

public class Table {
    public string Name {get; internal set; }
}

public class Database {
    public IList<Table> Tables { get; private set;}

    public Database(){
        this.Tables = new List<Table>();
    }
}
A: 

This is a common need found in classes representing your domain model, where you want your objects to have a publicly exposed read-only property for the ID, which must be setted internally. A solution I've used in the past is to use a method as a setter:

public interface ITable
{
    string Name { get; }
}

internal interface ITableInternal
{
   void SetName(string value);
}

public class Table : ITable, ITableInternal
{
    public string Name { get; }

    public void SetName(string value)
    {
       // Input validation

       this.Name = value;
    }
}

public class Database
{
    public Table CreateTable()
    {
        Table instance = new Table();
        ((ITableInternal)instance).SetName("tableName");

        return table;
    }    
}
Enrico Campidoglio
That may be good for Java, but .Net offers a better solution of property with different protection levels for its accessors.
I agree. My solution would also work well if targeting the .NET Framework 1.0/1.1 with C# 1.0, since the possibility to specify different access modifiers for the getters and setters of a property came with C# 2.0.
Enrico Campidoglio
A: 

Actually, I'd recommend hiding the setter-interface entirely as a private interface:

public interface ITable
{
   string Name { get; }
}

public class Database
{

    private interface IInternalTable 
    {
       string Name { get; set; }
    }

    private class Table : ITable, IInternalTable
    {
        public string Name { get; set; }
        string ITable.Name { get { return Name; } }
    }

    private List<IInternalTable> tables;

    public List<ITable> Tables
    {
       get { return this.tables; }
    }
}

That way, nobody other than Database can modify the items in Database.Tables.

scraimer