3

Not sure I'm able to formulate this question in a way someone would simply understand, so lets have a cool marketing example:

public class Part
{
    public MemberType member;
    ...
}

public class Product
{
    public Part part1;
    ...
}
...
Product product = new Product();

I need to modify the public product's part1. So, the natural method is to write something like:

product.part1 = new Part();

Now, an algorithm (let's say a sort of search one) would go through the product object and identify the part1 as an interesting part and returns reference to it:

Part Search(Product product)
{
    Part part = null;
    ...
    part = product.part1;
    ...
    return part;
}
...
interesting_part = Search(product);

We can alter the product object via the interesting_part like

interesting_part.member = whatever;

Now, the question: in c/c++ if the Product.part1 is pointer to Part and Search returns address of this pointer, we could replace the part1 just by assigning new value to this address. AFAIK this is not possible for c# reference:

interesting_part = new Part();

Just creates new object and copies its reference to the interresting_part, but without knowing the member parent (product object), we are not able to modify the (product.part1) reference, just its content. We would need second level of the reference.

Is there something like "ref reference" type which would accept reference addresses? In such hypothetical case the search would return ref Part and assigning to such value would replace the referenced object with the new one.

Thanks.

sharpener
  • 1,383
  • 11
  • 22

6 Answers6

1

You could create a Reference class

class Reference<T>
{
  private Func<T> m_Getter;  
  private Action<T> m_Setter;


  public Reference(Func<T> getter, Action<T> setter)
  {
    m_Getter = getter;
    m_Setter = setter;
  }

  public T Value
  {
    get{return m_Getter();}
    set{m_Setter(value);}
  }
}

Now you can say

Reference<Part> Search(Product product)
{
  Part part = null;
  ...
  part = product.part1;

  var reference=new Reference<Part>(()=>product.part, (value)=>product.part1=value);

  return refernce;
}

var partReference = Search(product);
partReference.Value = someNewPart;
Sean
  • 60,939
  • 11
  • 97
  • 136
  • 1
    I have done something similar and called it accessor, but seemed overcomplicated to me... Nice to see it's not so off topic. – sharpener Jan 21 '14 at 13:45
0

In a very similar situation, I keep a reference of the parent in each child object. Simple and works.

public class Part
{
    public MemberType member;
    ...

    public Product parent;

    Part(Product p)
    {
         parent = p;
    }
}

public class Product
{
    public Part part1;
    ...
}
dotNET
  • 33,414
  • 24
  • 162
  • 251
  • Yes, this seems to be a suitable workaround, but for complex structures and different data types the parent reference is going to be more complicated, and the single variable mutable reference would be elegant solution... Thanks anyway. – sharpener Jan 21 '14 at 13:37
0

I don't think you can do that. You would need to mutate a reference to you product object, or have some other added layer of reference.

tallseth
  • 3,635
  • 1
  • 23
  • 24
0

So you need to build a Proxy object. The Product would get a reference to the Proxy and the (hidden) Part can be exchanged. This is a common OO design pattern. Of course the Proxy can delegate method calls to the Part.

Ronald
  • 2,842
  • 16
  • 16
0

As far as I know, there isn't any way to alter an object's "parent" without having a reference to it. So I believe the official answer to your question as written is "no".

That said, there are many ways to accomplish the task as written. The easiest option is to add a reference to the parent from the part object. You end up with something like:

public class Part
{
    public Product parentProduct;
    public MemberType member;
    ...
}

Now whenever you have a part object you also know what product the part goes with (IF it does indeed go with a part at all). This is not necessarily a bad coding style but there certainly are pitfalls. You can update the product, but forget to update the parts in that product, you are coding so that parts have one product, but what if that part has many products? You can see how this works, but it can get complicated.

Taking this and making it more generic you can have reference the parent as an object type. That looks like:

public class Part
{
    public object parent;
    public MemberType member;
    ...
}

Now when you want to use the parent you can write something like:

var parentProduct = myPart.parent as Product;

This will convert the parent to a product or will assign null if the parent is not of the type Product. Now parts can have parents of any given type you would want and you have made the pattern more flexible.

One final pattern I know people use frequently is delegates. This allows you to pass in a function effectively modifying the way "search" is working. Say what you really want to do is search, then process the results in some manner, but you want that processing to be flexible (this may be what you were doing with the results). In that case, you can use delegates as follows:

    // define the delegate
    public delegate void ProcessResultDelegate(Product result, Part interestingPart);

    // an example search function
    public static void RunSearch(IEnumerable<Product> products, ProcessResultDelegate processingHelper)
    {
        // run the search... then call the processing function
        processingHelper(searchResult, interestingPart);
    }

This pattern is more useful when you want to modify the behavior of a routine rather than the return value from that routine.

Anyways, hope these patterns help some!

drew_w
  • 10,320
  • 4
  • 28
  • 49
0

If you want to change the field, you can do this,

class Program
{
    static void Main(string[] args)
    {
        var holder = new Holder();
        holder.CurrentPart = new Part() { Name = "Inital Part" };
        Console.WriteLine(holder.CurrentPart.Name);
        TestRef(ref holder.CurrentPart);
        Console.WriteLine(holder.CurrentPart.Name);
        Console.ReadKey();
    }

    public static void TestRef(ref Part part)
    {
        part = new Part() { Name = "changed" };
    }
}

public class Part
{
    public string Name;
}

public class Holder
{
    public Part CurrentPart;
}

This won't work with property, indexers and so.

Mat J
  • 5,422
  • 6
  • 40
  • 56
  • This was my first thought as well, but I suspect that OP is looking to _return_ a reference from a method and then use it (from how he states his question). From what I know of C# it's just not possible to use the ref keyword on return values. – wasatz Jan 21 '14 at 13:35
  • Your suspicion seems to be right, my bad. I think I'll leave it as an example for the maximum possible extent. – Mat J Jan 21 '14 at 13:58