0

I have an Object class that allows objects to be linked together.

A -> B -> C (one way linking)

When a link is formed between two objects by calling Link(IObject other), I want to set IsReferenced on the Next object.

So in the above example, A references B, but B does not reference A, B just has it's IsReferenced property set to true.

However, I only want the IsReferenced setter to be available to classes that implement the IObject interface. i.e the IsReferenced should only be able to be set inside the Object class, outside code should not be able to set it.

However, the code fails to compile as IsReferenced when accessed via the interface is read only.

 public interface IObject
{
    bool IsReferenced { get; }
    IObject? Next { get; }
    void Link(IObject next);
}

public class Object : IObject
{
    public bool IsReferenced { get; }
    public IObject? Next { get; private set; }

    public void Link(IObject next)
    {
        Next = next;
        next.IsReferenced = true;
    }
}

I can resolve the issue by doing the following :

public void Link(IObject next)
{
    Next = next;
    ((Object)next).IsReferenced = true;
}

But this won't work for my scenario, as I need to be able to Mock<IObject>

Is there a better solution other than making the IsReferenced a public setter?

7
  • 1
    Can you do other.Link(this)? Commented Oct 12, 2023 at 13:10
  • 1
    How is the actual Link represented? Other than setting a bool, I don't see the link after the method has executed. If you do that, I'd actually derive the value of the IsReferenced property off of that link reference existing or not. Commented Oct 12, 2023 at 13:10
  • No, wait, that will create an infinite loop... Maybe only perform the logic inside Link() if !IsReferenced Commented Oct 12, 2023 at 13:11
  • 1
    "its a one way link." - No it's not. As is, it is no link at all. You cannot traverse. As is, you wouldn't even know if the current Object is the source or the target of a "link". Commented Oct 12, 2023 at 13:13
  • 1
    @Fildor I have updated the description to better explain my scenario. Commented Oct 12, 2023 at 13:27

1 Answer 1

0

Is using a helper method to 'activate' IsReferenced an option for you?

By calling a helper method on the linked object with the object that has just linked it, the linked object can itself verify that it has in fact been referenced.

Here is a suggestion where OnLinkedBy() is the helper method:

public interface IObject
{
    bool IsReferenced { get; }
    IObject? Next { get; }
    void Link(IObject next);
    void OnLinkedBy(IObject other);
}

public class Object : IObject
{
    private IObject? _next { get; set; }

    public bool IsReferenced { get;  private set; }
    
    public IObject? Next
    {
        get => _next;
        private set
        {
            _next = value;
            
            if (_next is not null)
            {
                _next.OnLinkedBy(this);
            }
        }
    }
    
    public void Link(IObject next) => Next = next;
    
    public void OnLinkedBy(IObject other)
    {
        if (other.Next == this)
        {
            IsReferenced = true;
        }
    }
}

Now, if you do

var objectA = new Object();
var objectB = new Object();

objectA.Link(objectB);

Console.WriteLine("ObjectA is linked: " + (objectA.Next != null));
Console.WriteLine("ObjectA is referenced: " + objectA.IsReferenced);
Console.WriteLine("ObjectB is linked: " + (objectB.Next != null));
Console.WriteLine("ObjectB is referenced: " + objectB.IsReferenced);

the output will be:

ObjectA is linked: True
ObjectA is referenced: False
ObjectB is linked: False
ObjectB is referenced: True


Note: If you also want to be able to dereference, this simple approach will not cover your need.

Sign up to request clarification or add additional context in comments.

4 Comments

This is no different to just having IsReferenced be a public setter. The point is that IsReferenced should be maintained by the class implementing IObject, and should not be publicly available for anyone to change it.
@wforl I do not agree that it was 'no different', as no outside object could set IsReferenced to false. But I do understand it was not what you were looking for. I have updated my answer and replaced the original helper method with a helper method that takes an object as an input parameter, so that the linked object can verify on its own that it has in fact been linked. I believe it is closer to something you could accept using, although perhaps not exactly what you are aiming for.
Thanks but it's a bit convoluted and exposes a new method on the interface that really doesn't belong, but I guess there is no clean way.
Good points. I could not find a cleaner way myself, but am eager to see if someone posts an elegant approach.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.