具有静态列表的C#基类在实例化类型之间是不同的?

时间:2016-03-07 11:48:38

标签: c# static-members

我需要为我的对象创建唯一的ID,可以在应用程序实例之间保存和加载。

我在当前的实现中使用它,但这意味着我的每个类都需要几乎相同的代码段,因此我决定使用此代码创建一个基类,然后从中继承。代码如下。我唯一的问题是因为我在基类中有一个静态列表,所有继承的类类型都会被添加到同一个列表中。

因此,我如何更改代码以便列出'项目'类型之间是不同的列表吗?

澄清。如果我有两个班级列出这个: Foo:UniqueObject Bar:UniqueObject 我希望Foo和Bar拥有自己的静态列表

abstract class UniqueObject
{
    static protected List<UniqueObject> items = new List<UniqueObject>();
    static Random rnd = new Random();

    int id;

    public int Object_ID { get { return id; } }

    protected UniqueObject()
    {
        id = generateUniqueID();
        items.Add(this);
    }

    protected UniqueObject(int Object_ID)
    {
        // Ensure the passed ID is unique
        if (!isIdUnique(Object_ID))
        {
            // if not it does not get added to the items list and an exception is thrown.
            throw new ArgumentNullException("Object ID is not unique. Already being used by another object.");
        }

        // If we get here then must have been unique so add it.
        items.Add(this);
    }

    /// <summary>
    /// Generates the unique identifier.
    /// </summary>
    /// <returns>The unique ID</returns>
    private int generateUniqueID()
    {
        // get a random number
        int val = rnd.Next();

        // check it is unique, if not get another and try again.
        while (!isIdUnique(val))
        {
            val = rnd.Next();
        }

        return val;
    }

    /// <summary>
    /// Checks that the passed ID is unique against the other
    /// objects in the 'items' list.
    /// </summary>
    /// <param name="ID">The identifier.</param>
    /// <returns></returns>
    private bool isIdUnique(int ID)
    {
        foreach (UniqueObject c in items)
        {
            if (c.id == ID)
                return false;
        }
        return true;
    }
}

我相信我可以使用Generics实现这一点,所以我可以将类和列表更改为:

abstract class UniqueObject<T>
{
    static protected List<T> items = new List<T>();

但这会给行项目添加其他错误。添加(此)。

任何帮助都会得到满足。

2 个答案:

答案 0 :(得分:1)

如果您想要一个具有以下属性的唯一ID:

1)在当前应用领域中是唯一的

2)即使处理应用程序的多个实例,值也是唯一的。

然后你需要考虑其中一个解决方案:

1)生成GUIDS

2)拥有一个独特的服务器&#34;为您生成的ID(可以为您的ID提供服务的公共服务器)

3)如果您确切知道自己拥有多少个应用程序实例,则可以定义一个&#34;系列&#34;每个实例的唯一ID。

最后,您需要将unicity的概念抽象为一个单独的服务,您可以在应用程序的任何层/层中移动。你的对象不能包含关于unicity的逻辑,这个概念是一个单独的问题,你必须在其他组件中处理它。请应用关注点分离模式。

所以这是我的实施(如果我是你)

data['Date'] >= date

我写了一个这样的测试方法:

public interface IEntityWithUniqueId
{
    void SetUniqueId(string uniqueId);

    string UniqueId { get; }
}

public interface IUniqueIdsProvider
{
    string GetNewId();
}

public class UniqueObject : IEntityWithUniqueId
{
    public string UniqueId { get; private set; }

    void IEntityWithUniqueId.SetUniqueId(string uniqueId)
    {
        UniqueId = uniqueId;
    }
}

public class MyObjects : UniqueObject
{

}

public class RemoteUniqueIdsProvider : IUniqueIdsProvider
{
    public string GetNewId()
    {
        // calling a service ...., grab an unique ID
        return Guid.NewGuid().ToString().Replace ("-", "");
    }
}

public class UniqueObjectsFactory<T> where T : IEntityWithUniqueId, new ()
{
    private IUniqueIdsProvider _uniqueIdsProvider;
    public UniqueObjectsFactory(IUniqueIdsProvider uniqueIdsProvider)
    {
        _uniqueIdsProvider = uniqueIdsProvider;
    }

    public T GetNewEntity()
    {
        var x = new T();
        x.SetUniqueId(_uniqueIdsProvider.GetNewId ());

        return x;
    }
}

解释以上内容: 1)接口IEntityWithUniqueId定义了一个&#34; unique&#34;对象必须在您的应用程序中看起来像,因此它是一个具有UniqueId属性的对象,也是一个特殊的方法:SetUniqueId。我没有用get和set创建属性UniqueId因为&#34; set&#34;将是一个基础架构操作,但get将是一个开发人员API。

2)IUniqueIdsProvider接口告诉您独特的ID提供程序的外观。它必须有一个简单的方法:GetNewId();为您提供独特的身份证明。实现可以在任何地方(在服务器上,本地等)

3)UniqueObject类。此类是所有唯一对象的基类。

4)UniqueObjectsFactory。这是为您提供新的独特对象的类。从磁盘加载对象时,您必须从生成唯一ID的假设开始,因此在加载它们时,您不必再次处理检查单一性。

答案 1 :(得分:1)

关于使用泛型的最后一句话,我想你可以这样做:

abstract class UniqueObject<T> where T : class

然后

items.Add(this as T);

这应该有效,如果您没有明确使用this as TUniqueObject<>在运行时不会失败。

我不确定如何提倡在泛型类型(and you should not do that)上使用静态成员,但这应该至少有效

更新:是的,seems to work

建议

在我的回答中,我试图准确回答你的要求。但是如上所述,如果您需要的只是对象的唯一ID,并且在创建它们时检查它是否不重复,您可以:

  1. 使用GUID,忘记检查。 GUID碰撞在理论上是可能的......但它会发生吗?在正常情况下,更有可能不是。即使您在一年内创建了一万亿个GUID,但是在您找到重复项之前,陨石撞击计算机几次

    会导致程序崩溃的可能性更高

  2. 但是,如果你想检查它并且绝对确定(实际上这是公平的事情),这可能会更容易,而且你不需要存储一个列表每个类型的完整对象来做这个...看看这个简单的基类,它将以你想要的方式做你想做的事情:

    abstract class UniqueObject : IDisposable
    {
       static protected HashSet<Guid> Guids = new HashSet<Guid>();
       Guid _id;
    
       public Guid ObjectID { get { return _id; } }
    
       protected UniqueObject()
       {
         do
         {
           _id = Guid.NewGuid();
         } while(Guids.Contains(_id));           
         Guids.Add(_id);
       }  
    
       protected UniqueObject(Guid guid)
       {
         if(Guids.Contains(guid))
           throw new ArgumentNullException("Object ID is not unique. Already being used by another object.");
         _id = guid;
       }
    
       // Make a better implementation of IDisposable
       public void Dispose()
       {
         guids.Remove(_id);
       }
    }
    
  3. 就是这样。如果您仍想使用int代替Guid,则可以将其更改为int,并具有以下内容:

    // static members
    static protected Random rnd = new Random();
    static protected HashSet<int> ids = new HashSet<int>();
    // ... in the constructor:
    do
    {
      _id = rnd.Next();
    } while(ids.Contains(_id));
    

    看起来与之前的相似