C# 从C中存储的缓存初始化构造函数#

C# 从C中存储的缓存初始化构造函数#,c#,inheritance,memory-management,object,instantiation,C#,Inheritance,Memory Management,Object,Instantiation,我不知道该如何确切地描述这个问题,但这里是。我有一个映射到SQLite数据库中的对象的类层次结构。我已经编写了所有在.NET对象和数据库之间进行通信的非平凡代码 我有一个基本接口,如下所示: public interface IBackendObject { void Read(int id); void Refresh(); void Save(); void Delete(); } 这是对任何对象的基本CRUD操作。然后我实现了一个基类,它封装了大部分功能

我不知道该如何确切地描述这个问题,但这里是。我有一个映射到SQLite数据库中的对象的类层次结构。我已经编写了所有在.NET对象和数据库之间进行通信的非平凡代码

我有一个基本接口,如下所示:

public interface IBackendObject
{
    void Read(int id);
    void Refresh();
    void Save();
    void Delete();
}
这是对任何对象的基本CRUD操作。然后我实现了一个基类,它封装了大部分功能

public abstract class ABackendObject : IBackendObject
{
    protected ABackendObject() { } // constructor used to instantiate new objects
    protected ABackendObject(int id) { Read(id); } // constructor used to load object

    public void Read(int id) { ... } // implemented here is the DB code
}
最后,我有了具体的子对象,每个子对象在数据库中都有自己的表:

public class ChildObject : ABackendObject
{
    public ChildObject() : base() { }
    public ChildObject(int id) : base(id) { }
}
到目前为止,就我的所有目的而言,这一切都很好。子类有几个回调方法,基类使用这些方法正确地实例化数据

我现在想让这个稍微有效一点。例如,在以下代码中:

public void SomeFunction1()
{
    ChildObject obj = new ChildObject(1);
    obj.Property1 = "blah!";
    obj.Save();
}

public void SomeFunction2()
{
    ChildObject obj = new ChildObject(1);
    obj.Property2 = "blah!";
    obj.Save();
}
在本例中,我将构造两个全新的内存实例化,根据调用SomeFunction1和SomeFunction2的顺序,可能不会保存Property1或Property2。我想要实现的是让这两个实例化以某种方式指向同一个内存位置——我认为如果我使用“new”关键字,这是不可能的,所以我一直在寻找关于如何继续的提示

理想情况下,我希望在我的
ABackendObject
类中存储所有加载对象的缓存,并在请求时返回对已加载对象的内存引用,或者从内存加载对象(如果该对象不存在)并将其添加到缓存中。我有很多代码已经在使用这个框架了,所以我当然要改变很多东西才能让它工作,但我只是想知道一些如何继续的技巧


谢谢

您需要的是对象工厂。将
ChildObject
构造函数设为私有,然后编写一个静态方法
ChildObject.Create(int index)
,该方法返回
ChildObject
,但在内部确保使用相同索引的不同调用返回相同的对象。对于简单的情况,索引=>对象的简单静态哈希就足够了。

您需要的是对象工厂。将
ChildObject
构造函数设为私有,然后编写一个静态方法
ChildObject.Create(int index)
,该方法返回
ChildObject
,但在内部确保使用相同索引的不同调用返回相同的对象。对于简单的情况,索引=>对象的简单静态散列就足够了。

如果您想存储加载对象的“缓存”,您可以很容易地让每种类型维护一个
字典,其中保存加载的对象,并按其ID键控

不要使用构造函数,而是构建一个检查缓存的工厂方法:

public abstract class ABackendObject<T> where T : class
{
     public T LoadFromDB(int id) {
         T obj = this.CheckCache(id);
         if (obj == null)
         { 
             obj = this.Read(id); // Load the object
             this.SaveToCache(id, obj);
         }
         return obj;
     }
} 
公共抽象类ABackendObject,其中T:class
{
公共T LoadFromDB(内部id){
T obj=this.CheckCache(id);
if(obj==null)
{ 
obj=this.Read(id);//加载对象
这个.SaveToCache(id,obj);
}
返回obj;
}
} 
如果您将基类设置为泛型,并将其读取为虚拟的,那么您应该能够在没有太多代码重复的情况下提供大部分这类功能。

如果您想存储加载对象的“缓存”,您可以轻松地让每种类型维护一个由其ID键入的保存加载对象的
字典

不要使用构造函数,而是构建一个检查缓存的工厂方法:

public abstract class ABackendObject<T> where T : class
{
     public T LoadFromDB(int id) {
         T obj = this.CheckCache(id);
         if (obj == null)
         { 
             obj = this.Read(id); // Load the object
             this.SaveToCache(id, obj);
         }
         return obj;
     }
} 
公共抽象类ABackendObject,其中T:class
{
公共T LoadFromDB(内部id){
T obj=this.CheckCache(id);
if(obj==null)
{ 
obj=this.Read(id);//加载对象
这个.SaveToCache(id,obj);
}
返回obj;
}
} 

如果将基类设置为泛型,并将其读取为虚拟的,则应该能够在不进行大量代码复制的情况下提供大部分功能。

如果使用.NET Framework 4,则可能需要查看
System.Runtime.Caching
命名空间,它为您提供了一个非常强大的缓存体系结构


如果您使用的是.NET Framework 4,您可能需要查看
System.Runtime.Caching
命名空间,它为您提供了一个非常强大的缓存体系结构


听起来非常适合这样的参考计数

    #region Begin/End Update
    int refcount = 0;
    ChildObject record;
    protected ChildObject ActiveRecord
    {
        get 
        {
            return record;
        }

        set 
        {
            record = value;
        }
    }

    public void BeginUpdate()
    {
        if (count == 0)
        {
            ActiveRecord = new ChildObject(1);

        }

        Interlocked.Increment(ref refcount);
    }

    public void EndUpdate()
    {
        int count = Interlocked.Decrement(ref refcount);

        if (count == 0)
        {
            ActiveRecord.Save();
        }
    }
    #endregion


    #region operations

    public void SomeFunction1()
    {
        BeginUpdate();

        try
        {
            ActiveRecord.Property1 = "blah!";
        }
        finally
        {
            EndUpdate();
        }
    }

    public void SomeFunction2()
    {
        BeginUpdate();

        try
        {
            ActiveRecord.Property2 = "blah!";
        }
        finally
        {
            EndUpdate();
        }
    }


    public void SomeFunction2()
    {
        BeginUpdate();

        try
        {
            SomeFunction1();
            SomeFunction2();
        }
        finally
        {
            EndUpdate();
        }
    } 
    #endregion

听起来很适合这样的参考计数

    #region Begin/End Update
    int refcount = 0;
    ChildObject record;
    protected ChildObject ActiveRecord
    {
        get 
        {
            return record;
        }

        set 
        {
            record = value;
        }
    }

    public void BeginUpdate()
    {
        if (count == 0)
        {
            ActiveRecord = new ChildObject(1);

        }

        Interlocked.Increment(ref refcount);
    }

    public void EndUpdate()
    {
        int count = Interlocked.Decrement(ref refcount);

        if (count == 0)
        {
            ActiveRecord.Save();
        }
    }
    #endregion


    #region operations

    public void SomeFunction1()
    {
        BeginUpdate();

        try
        {
            ActiveRecord.Property1 = "blah!";
        }
        finally
        {
            EndUpdate();
        }
    }

    public void SomeFunction2()
    {
        BeginUpdate();

        try
        {
            ActiveRecord.Property2 = "blah!";
        }
        finally
        {
            EndUpdate();
        }
    }


    public void SomeFunction2()
    {
        BeginUpdate();

        try
        {
            SomeFunction1();
            SomeFunction2();
        }
        finally
        {
            EndUpdate();
        }
    } 
    #endregion

我认为你的计划或多或少是正确的。您可以创建创建子对象的工厂(并可以跟踪“活动”实例),也可以跟踪已保存的实例,因此,当调用Save方法时,它会识别出
ChildObject
的第一个实例与
ChildObject
的第二个实例相同,并将数据从第二个实例深度复制到第一个实例。从编码的角度来看,这两种方法都相当重要,并且都可能涉及覆盖实体上的相等方法。我倾向于认为使用第一种方法不太可能导致错误


另外一个选择是使用现有的Obect关系映射包,比如或在对象和数据库之间进行映射。我知道NHibernate支持Sqlite,根据我的经验,它往往是需要对实体结构进行最少更改的。按照这条路线,您将获得ORM层跟踪实例的好处(并为您生成SQL),此外,您可能还将获得当前数据访问代码可能没有的一些更高级的功能。缺点是,这些框架往往有一条与之相关的学习曲线,根据您使用的框架,可能会对代码的其余部分产生不小的影响。因此,在学习框架和将代码转换为使用API的成本与收益之间进行权衡是值得的。

我认为您的做法或多或少是正确的。哟