从堆获取以前实例化的对象以获取变量引用

时间:2017-08-25 19:50:19

标签: c# asp.net oop object recursion

我有两个包含另一个类属性的类。

public class Client
{
    public Customer Customer { get; set; }

    public Client()
    {

    }
}

public class Customer
{
    public Client Client { get; set; }

    public Customer(int id)
    {
        // some retrieval logic by using id ...
    }
}

这是一个Factory类,它显示了我在编译时知道对象之前想要实现的概念。实际上,我不需要通过用户提供的数据反射来实例化它们。现在考虑到这一点,我希望将对方类的对象属性分配给该另一个类的先前创建的对象(例如下面)

public class Factory
{
    public Factory()
    {
        // this is all done via reflection at run-time in my real code
        Client client = new Client();
        client.Customer = new Customer(1); // id would be retrieve from a client property (not shown for simplicity sake)
        client.Customer.Client = client; // refer to the first object of client
    }
}

但是,利用以前提供的工厂类示例,我的代码中的客户端对象不在范围内,或者更高的是在堆栈上(各种属性是递归实例化的,如果更高的类具有相同类型的属性)它被跳过一个子后续类/对象(以避免无限递归)。

如何在工厂方法中使用类名或任何对象的属性,将属性指向先前实例化的对象,当它可能不在范围内时?

我正在考虑使用列表/字典来存储更高级别的对象引用,并通过递归传递它们并检查对象的类型是否与子后续属性的类型相匹配然后只使用存储在列表/字典中的对象来获取该属性。我想看看这是否是最好的方式,或者是否有另一种方式。

这纯粹是理论上的,可能使用也可能不使用。目标是从这些类创建任何时间和对象,所有相关类在第一个对象中都具有属性,这些属性包含从不为null /不能无限回复的相关类的实例化实例。

1 个答案:

答案 0 :(得分:0)

我建议您为CustomerClient使用工厂,只有一个小的增强功能:您将需要使用实现缓存的工厂。可以找到一个示例in this answer

构建Customer时,只需从缓存工厂填充Client即可。反之亦然。缓存机制将负责其余部分。当然,您希望将工厂注入为单例实例,以便缓存在使用工厂的所有代码中都是通用的。

客户工厂可能看起来像这样:

public class CustomerFactory : ICustomerFactory
{
    private readonly IClientFactory clientFactory;  //To be injected

    private readonly ConcurrentDictionary<int, ICustomer> customers = 
                 new ConcurrentDictionary<int, ICustomer>();

    public CustomerFactory(IClientFactory clientFactory)
    {
        this.clientFactory = clientFactory; //Injected
    }

    public ICustomer GetCustomer(int id)
    {
        ICustomer customer = this.customers.GetOrAdd(id, () => new Customer(id));
        if (customer.Client == null)
        {
            customer.Client = this.clientFactory.GetClient(customer.ClientID);
        }
        return customer;
    }
}

在上面的示例中,您将注意到在尝试设置Client属性之前,新实例化的Customer已添加到缓存中。这对于避免无限循环非常重要。如果您在客户进入缓存之前尝试检索客户端,则ClientFactory将无法找到它,并可能最终创建新实例。

另一方面,也许您不需要立即设置Client属性。毕竟,你现在有一个缓存机制,所以你可以懒得设置它。我们可以从GetCustomer ...

中删除代码
    public ICustomer GetCustomer(int id)
    {
        return this.customers.GetOrAdd(id, () => new Customer(id));
    }

...仅在需要时检索客户端。

class Customer
{
   public Client Client
   {
       get
       {
           return this.clientFactory.GetClient(this.ClientID);
       }
   }
}

虽然一遍又一遍地调用ClientFactory似乎很昂贵,但所有这一切都是在字典中快速查找。如果呼叫者甚至不需要客户端,我们将保存到数据库的往返。

除了您不需要传递任何引用之外,这个想法与您在问题结束时提出的想法大不相同。唯一需要的参考是对工厂的参考。