views:

97

answers:

2

I want to have an overloaded constructor where I change the value of the base class depending if the "isFirstPost" is set. If it's a first post, I want the rowkey = 000000. If it's not a first post, then make it a number.

Don't really think of this as an Azure problem... but I'm more interested in the C# language and making a conditional parameter influence the setting of the base class. I'm not sure how to do this.

public class ForumPost : TableServiceEntity
    {
        public ForumPost(string partitionKey, string rowKey): base(partitionKey, rowKey)
        {
        }
        public ForumPost(ForumThread ParentThread, bool IsFirstPost)
        {
            if (IsFirstPost)
            {
                //call constuctor with special values for base class
                //set baseclass rowkey = 0000000
            }

            else {
             //set baseclass rowkey = 1111111111
              }
         }
}
+3  A: 

This isn't possible because the base constructor must be called before the current class's constructor. What you can do is define a static function that will pass the correct id to the base constructor.

public class ForumPost : TableServiceEntity
{
    public ForumPost(ForumThread ParentThread, bool IsFirstPost)
        : base(ParentThread, GetID(IsFirstPost))
    {
    }

    static string GetID(bool IsFirstPost)
    {
        return IsFirstPost ? "00000" : "11111";
    }
}
Jake Pearson
-1 What's the difference between the base and the parent constructor? Aren't they one and the same? Also, if the logic involves instance members of the instance being constructed, this extract-static-method refactoring won't work.
Jordão
Good point. Fixed.
Jake Pearson
Great. Removed the downvote. I just think that for this example, a simple conditional expression in the base method call would suffice.
Jordão
+2  A: 

Just do this:

public class ForumPost : TableServiceEntity {
  public ForumPost(ForumThread ParentThread, bool IsFirstPost) 
    : base("partitionkey", IsFirstPost ? "0000000" : "1111111") {
  }
}

Note: I don't know what you want to pass as a partition key though.

UPDATE: to understand what this construct can take, we can take a look at the C# specification.

In the C# grammar we find these entries:

constructor-initializer:
  : base ( argument-listopt )
  : this ( argument-listopt )
argument-list:
  argument
  argument-list , argument
argument:
  expression
  ref variable-reference
  out variable-reference

This, in turn, expands to all kinds of expressions that the language supports (look in section C.2.4). This includes method invocations, mathematical expressions, the ternary conditional operator, and many others.

In section 10.11.1 (Constructor initializers) of the spec, we find this:

The scope of the parameters given by the formal-parameter-list of an instance constructor declaration includes the constructor initializer of that declaration. Thus, a constructor initializer is permitted to access the parameters of the constructor. [...] An instance constructor initializer cannot access the instance being created. Therefore it is a compile-time error to reference this in an argument expression of the constructor initializer, as is it a compile-time error for an argument expression to reference any instance member through a simple-name.

So, you can treat it just like any method invocation. You have access to the arguments to the constructor, but not to the instance being created. Which means that, if your logic involves any instance members of the instance being constructed, you'll have to redesign your class to separate them.

I think the answer that I gave (with the conditional operator) is the most straighforward for your example. We can also take it to the other extreme, and use a factory method to get a strategy for that logic:

public class ForumPost : TableServiceEntity {
  public ForumPost(ForumThread ParentThread, bool IsFirstPost) 
    : base("partitionkey", 
        RowKeyStrategyFactory.Create().ResolveRowKey(IsFirstPost)) {
  }
}

Here you see a static factory method call, that returns an instance of a strategy, followed by an instance call on the strategy virtual method that runs the desired logic. The concrete strategy class would be decided based, e.g., in configuration, and would contain the logic to generate the right row key given its parameter.

As you can see, there's no single answer for the question, only you can decide based on your design and constraints. But by understanding what the construct can handle, you're better informed to make a good decision.

Jordão
Thats good for a small example like this one, but I wonder how complex of a situation this approach can handle
MakerOfThings7
I think Jake's answer is more general, since it works even if the logic is not easily contained in a single expression.
Steven Sudit
@MakerOfThings7: It can handle an expression involving the constructor parameters.
Jordão
@Steven Sudit: My answer is more convenient for the example. You can have any expression there, including method calls. You just can't call instance methods on the instance being constructed.
Jordão
Yes, the general case is to call a static method, as Jake's code showed.
Steven Sudit
@Steven: No, the general case is to use an _expression_. A static method call that returns a value is just one type of expression.
Jordão
I've updated the answer with more clarifications. I hope it's clear now why I used a [simple expression](http://en.wikipedia.org/wiki/Occam%27s_razor) in my answer.
Jordão