PilotMelch
PilotMelch

Reputation: 7

Why is my const or static member not initialized?

I've been both scratching and banging my head on this one. I suspect I;m just being daft here, but I can't seem to get a const, or static, member to initialize so I can use it throughout a class.

Here's an example that demonstrates my problem (or rather my misunderstanding):

using System;

namespace ConstExample
{
  public class HasImmutableMember
  {
    // static private double fSectionLengthTolerancePerInch = 1 / (20 * 12);  // tolerance is 1" per every 20'
    private const double fSectionLengthTolerancePerInch = 1 / (20 * 12);  // tolerance is 1" per every 20'

    static HasImmutableMember()
    {
      Console.WriteLine("static c'tor: " + fSectionLengthTolerancePerInch);
    }

    public HasImmutableMember()
    {
      Console.WriteLine("instance c'tor: " + fSectionLengthTolerancePerInch);
    }
  }

  public class Program
  {
    public void Main(string[] args)
    {
      HasImmutableMember instance = new HasImmutableMember();
    }
  }
}

Console output is:

static c'tor: 0
instance c'tor: 0

Can't set a breakpoint at the const member declaration, but if I use the static version, I can. Both fail to give me what I want. The static member declaration does get hit prior to either the static c'tor or the instance c'tor. And as expected the static c'tor gets hit before the instance c'tor. But in both the static and instance c'tor's the value of my member is 0 rather than the initialized value.

What am I missing?

Upvotes: 0

Views: 224

Answers (5)

jamir
jamir

Reputation: 62

change

private const double fSectionLengthTolerancePerInch = 1 / (20 * 12);

to

private const double fSectionLengthTolerancePerInch = 11.0

Upvotes: -2

Eric Lippert
Eric Lippert

Reputation: 660159

This is a classic "conversion too late" defect which I wish the C# compiler warned about. You are doing all the arithmetic in integers, and then assigning the result to a double. The result is an integer, and 1 / 240 in integers is zero. Do the arithmetic in doubles: 1.0 / 240.0.

We also see this defect involving non-constants, eg,

percentDone = doneSoFar / totalWork;

If the dividends are integers and the result is a double then the result is likely to be zero.

Also watch out for the same "conversion too late" defect involving multiplication:

double microseconds = seconds * 1000000;

if seconds is int and more than a couple thousand then this will overflow in integers before it assigns to double, instead of what you want, which is to convert to double first and do the multiplication in doubles. Again, it should be 1000000.0 to hint to the compiler that you wish the operation to be done in higher precision.

Upvotes: 5

Idos
Idos

Reputation: 15320

You need to cast at least one of your integers since you are dividing two integers and this results in an integer as well (which gets rounded to 0 in your case):

private const double fSectionLengthTolerancePerInch = (double)1 / (20 * 12); 

And then you can use:

Console.WriteLine("instance c'tor: " + fSectionLengthTolerancePerInch);
>>> 0.00416666666666667

Upvotes: 0

tchelidze
tchelidze

Reputation: 8318

Reason is that there is Integer division.

When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded.88) If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.

Try following .

private const double fSectionLengthTolerancePerInch = 1.0 / (20 * 12); 

Upvotes: 1

PiotrWolkowski
PiotrWolkowski

Reputation: 8782

You operate on integers 1 / (20 * 12). The result is actually 0. You have to have at least one number to be double to get the result as double: 1.0 / (20 * 12).

Upvotes: 0

Related Questions