Search code examples
c#constructorcalllazy-loadinglazy-evaluation

C# Late method call from constructor with properties (possible lazy evaluation)


I'm developing some kind of TCP-server and have concluded one nasty thing.

Here is a piece of code:

public void GetSessionId(byte[] secretPhrase)
{
    var message = new ZllnpMessage
    {
        Head = CreateHeader(Session.Opcodes.GetSessionToken),
        Body = CreateBodyContent(secretPhrase)
    };

    message.CalculateHash(saveHash: true);

    var data = message.ToBinary();
    socket.Send(data);
    socket.Receive();
}

Here you can see the line:

message.CalculateHash(saveHash: true);

It's required to calculate control sum for each message.

There is a simple solution: just pass head & body to constructor and then calcuate inside ZllnpMessage.

OK, that's an option, but what if I would like to do the next:

Initialize object both with properties and provide it something like that:

var message = new ZllnpMessage(saveHash: true)
{
    Head = CreateHeader(Session.Opcodes.GetSessionToken),
    Body = CreateBodyContent(secretPhrase)
};

Then later, spy for the (maybe using events with Lazy) property value changes to implement later autocall.

So, I'm rather confusing what is better way to do? Can you give me a piece of advice, please?

Please, don't ask me about:

  • why TCP?
  • why not TPL with Task?

Answers:

  • TCP, because of project requirements
  • Not TPL, because I'm using old threading model with manual control, semaphores etc (I know, that it's hard and etc...)

PS

Also, question is about late method call from constructor :) Not the project design


Solution

  • It looks like your question is "How can I control hash calculation by passing a value to the constructor". If you want automatic hash calculation in property setters, which you optionally can switch off, you'll have to implement it anyway.

    You can do so as such:

    public class ZllnpMessage
    {
        private bool _autoHash;
    
        private string _head;
        public string Head 
        { 
            get { return _head; } 
            set 
            {
                _head = value;
                if (_autoHash)
                {
                    CalculateHash();
                }
            } 
        }
    
        public ZllnpMessage(bool autoHash)
        {
            _autoHash = autoHash;
        }
    
        public byte[] CalculateHash()
        {
            // return hash
        }
    
        public byte[] ToBinary()
        {
            // return serialized message
        }
    }
    

    However, the most straightforward way to do hash calculation is only before serialization, so in ToBinary():

    public class ZllnpMessage
    {
        public string Head { get; set; }
    
        public byte[] CalculateHash()
        {
            // return hash
        }
    
        public byte[] ToBinary()
        {
            CalculateHash();
            // return serialized message
        }
    }