对象的“可写”引用

时间:2014-01-21 13:19:19

标签: c# pointers reference

我不确定我是否能够以某人简单理解的方式制定此问题,因此我们举一个cool营销示例:

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

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

我需要修改公开product的{​​{1}}。所以,自然的方法就是写下这样的东西:

part1

现在,一个算法(比如说一种搜索)将通过product.part1 = new Part(); 对象并将product标识为一个有趣的部分并返回对它的引用:

part1

我们可以通过Part Search(Product product) { Part part = null; ... part = product.part1; ... return part; } ... interesting_part = Search(product); 之类的

来改变product对象
interesting_part

现在,问题:在c / c ++中,如果interesting_part.member = whatever; 是指向Product.part1的指针而Search返回此指针的地址,我们可以替换{{1}只需为此地址指定新值即可。 AFAIK这不适用于c#reference:

Part

只需创建新对象并复制其对part1的引用,但不知道成员父(interesting_part = new Part(); 对象),我们无法修改(interresting_part)引用,只是它的内容。我们需要第二级参考。

是否有类似“ref reference”类型的内容可以接受引用地址?在这种假设的情况下,搜索将返回product并且分配给这样的值会将引用的对象替换为新的。

感谢。

6 个答案:

答案 0 :(得分:1)

您可以创建Reference

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);}
  }
}

现在你可以说

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;

答案 1 :(得分:0)

在非常类似的情况下,我在每个子对象中保留父对象的引用。简单而有效。

public class Part
{
    public MemberType member;
    ...

    public Product parent;

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

public class Product
{
    public Part part1;
    ...
}

答案 2 :(得分:0)

我认为你不能那样做。您需要改变对product对象的引用,或者添加一些其他引用层。

答案 3 :(得分:0)

所以你需要构建一个Proxy对象。产品将获得对代理的引用,并且可以交换(隐藏)部分。这是一种常见的OO设计模式。当然,Proxy可以将方法调用委托给Part。

答案 4 :(得分:0)

据我所知,没有任何方法可以在不引用对象的情况下更改对象的“父级”。所以我相信你写的问题的正式答案是“不”。

也就是说,有很多方法可以完成任务。最简单的选择是从零件对象添加对父级的引用。你得到的结果如下:

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

现在每当你有一个零件对象时,你也会知道零件所用的产品(如果它确实与零件一起使用)。这不一定是糟糕的编码风格,但肯定存在陷阱。您可以更新产品,但忘记更新该产品中的部件,您正在编码,以便部件有一个产品,但如果该部件有很多产品怎么办?你可以看到它是如何工作的,但它可能变得复杂。

考虑到这一点并使其更通用,您可以将父作为对象类型引用。看起来像是:

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

现在,当您想要使用父级时,您可以编写如下内容:

var parentProduct = myPart.parent as Product;

这会将父级转换为产品,或者如果父级不是Product类型,则将分配null。现在,零件可以包含您想要的任何给定类型的父级,并且您可以使模式更加灵活。

我知道人们经常使用的最后一种模式是代表。这允许您传入一个有效修改“搜索”工作方式的函数。说出你真正想做的是搜索,然后以某种方式处理结果,但是你希望这种处理是灵活的(这可能就是你对结果所做的)。在这种情况下,您可以按如下方式使用委托:

    // 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);
    }

当您想要修改例程的行为而不是该例程的返回值时,此模式更有用。

无论如何,希望这些模式有所帮助!

答案 5 :(得分:0)

如果您想更改field,可以执行此操作,

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;
}

这不适用于属性,索引器等。