C# &引用;“可写”;对对象的引用

C# &引用;“可写”;对对象的引用,c#,pointers,reference,C#,Pointers,Reference,我不确定我是否能够以一种人们能够简单理解的方式来阐述这个问题,所以让我们来看一个酷的营销示例: public class Part { public MemberType member; ... } public class Product { public Part part1; ... } ... Product product = new Product(); 我需要修改公共产品的第1部分。所以,自然的方法是写一些东西,比如: product.part1

我不确定我是否能够以一种人们能够简单理解的方式来阐述这个问题,所以让我们来看一个
酷的
营销示例:

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

public class Product
{
    public Part part1;
    ...
}
...
Product product = new Product();
我需要修改公共
产品
第1部分
。所以,自然的方法是写一些东西,比如:

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

Part Search(Product product)
{
    Part part = null;
    ...
    part = product.part1;
    ...
    return part;
}
...
interesting_part = Search(product);
我们可以通过
有趣的部分
更改
产品
对象,如

interesting_part.member = whatever;
现在,问题是:在c/c++中,如果
Product.part1
是指向
Part
的指针,并且搜索返回该指针的地址,我们可以通过向该地址分配新值来替换
part1
。恐怕这不可能作为c#参考:

interesting_part = new Part();
仅创建新对象并将其引用复制到
相互测试部分
,但在不知道成员父对象(
产品
对象)的情况下,我们无法修改(
产品.part1
)引用,只修改其内容。我们需要第二层的参考资料

是否有类似于“ref-reference”的类型可以接受引用地址?在这种假设情况下,搜索将返回
ref-Part
,并将该值赋值将引用对象替换为新对象


谢谢。

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

public class Part
{
    public MemberType member;
    ...

    public Product parent;

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

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

我认为你做不到。您需要修改对您
产品
对象的引用,或者添加一些其他引用层

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

您可以创建一个
引用

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);}
  }
}
类参考
{
私人Func m_Getter;
私人行动制定者;
公共引用(Func getter、Action setter)
{
m_Getter=Getter;
m_Setter=Setter;
}
公共价值
{
获取{return m_Getter();}
集合{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;
参考搜索(产品)
{
Part=null;
...
零件=产品。零件1;
var参考=新参考(()=>product.part,(值)=>product.part1=值);
返回参考;
}
var partReference=搜索(产品);
partReference.Value=someNewPart;

据我所知,没有对对象的引用,就无法更改对象的“父对象”。因此,我相信官方对你书面问题的回答是“不”

也就是说,有很多方法可以完成书面任务。最简单的选项是从零件对象添加对父对象的引用。你最终会得到这样的结果:

public class Part
{
    public Product parentProduct;
    public MemberType member;
    ...
}
var parentProduct = myPart.parent as Product;
现在,只要你有一个零件对象,你也知道零件与什么产品一起(如果它确实与零件一起)。这不一定是一种糟糕的编码风格,但肯定存在缺陷。您可以更新产品,但忘了更新该产品中的零件,您正在编码,以便零件具有一个产品,但是如果该零件具有多个产品呢?你可以看到它是如何工作的,但它可能会变得复杂

采用这种方法并使其更通用,您可以将父对象作为对象类型引用。这看起来像:

public class Part
{
    public object parent;
    public MemberType member;
    ...
}
现在,当您想使用父级时,可以编写如下内容:

public class Part
{
    public Product parentProduct;
    public MemberType member;
    ...
}
var parentProduct = myPart.parent as 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);
    }
//定义委托
公共委托无效处理结果删除(产品结果、部分利益部分);
//一个示例搜索函数
公共静态void运行搜索(IEnumerable products、ProcessResultDelegate processingHelper)
{
//运行搜索…然后调用处理函数
processingHelper(搜索结果、兴趣部分);
}
当您想要修改例程的行为而不是该例程的返回值时,此模式更有用


不管怎样,希望这些模式对你有所帮助

如果要更改
字段
,可以这样做

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

这对属性、索引器等不起作用。

您的
搜索
返回一个引用,而不是“对象”本身。您可以将引用包装在一个类中,并传递该包装的实例。保留对父类的引用。请参阅以下答案:@Eli谢谢,有用的链接。这也是我的第一个想法,但我怀疑OP希望从一个方法返回一个引用,然后使用它(从他陈述问题的方式)。根据我对C#的了解,在返回值上使用ref关键字是不可能的。你的怀疑似乎是对的,我的错。我想我会把它作为一个最大可能范围的例子。是的,这似乎是一个合适的解决办法,但对于复杂的结构和不同的数据类型,父引用将更加复杂,而单变量可变引用将是一个优雅的解决方案。。。不管怎样,谢谢。好吧,显然没有这样的语言结构:o(我做了类似的事情,称之为访问器,但对我来说似乎过于复杂了……很高兴看到它不是那么离题。