我需要为我的对象创建唯一的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>();
但这会给行项目添加其他错误。添加(此)。
任何帮助都会得到满足。
答案 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 T
,UniqueObject<>
在运行时不会失败。
我不确定如何提倡在泛型类型(and you should not do that)上使用静态成员,但这应该至少有效
更新:是的,seems to work
在我的回答中,我试图准确回答你的要求。但是如上所述,如果您需要的只是对象的唯一ID,并且在创建它们时检查它是否不重复,您可以:
使用GUID,忘记检查。 GUID碰撞在理论上是可能的......但它会发生吗?在正常情况下,更有可能不是。即使您在一年内创建了一万亿个GUID,但是在您找到重复项之前,陨石撞击计算机几次
会导致程序崩溃的可能性更高但是,如果你想检查它并且绝对确定(实际上这是公平的事情),这可能会更容易,而且你不需要存储一个列表每个类型的完整对象来做这个...看看这个简单的基类,它将以你想要的方式做你想做的事情:
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);
}
}
就是这样。如果您仍想使用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));
看起来与之前的相似