我正在尝试创建一个扩展方法,允许我以TimeSpan的形式在Now和一些用户请求的历史时间点之间创建一个随机时间.
例如:从现在到1小时之前的随机时间.
所以,我提出了以下Random(..)扩展方法.
我想让随机种子不是静态的,但是如果我把这种方法称为很多而且很快(例如在循环中),那么我认为种子(基于时间)对于真正的快速调用来说并不是真正随机的.真的吗?(似乎是,当我检查我的结果时)
public static DateTimeOffset Random(this DateTimeOffset value, TimeSpan timeSpan)
{
var random = new Random();
DateTimeOffset minDateTime = value.Subtract(timeSpan);
int range = ((DateTime.Today - minDateTime)).Hours;
return minDateTime.AddHours(random.Next(range));
}
Run Code Online (Sandbox Code Playgroud)
正如其他人所说,问题是new Random()使用当前时间来形成种子,并且你会多次获得相同的种子.
基本上你想创建相对较少的实例.由于Random不是线程安全的,您需要ThreadStatic或ThreadLocal<T>- 后者是.NET 4.0的新手.这是一个示例StaticRandom类(使用.NET 4.0),它允许您使用该Instance属性获取此线程的有效实例.请注意,在类型初始化时,将从当前时间设置计数器.然后将其用于连续种子.
using System;
using System.Threading;
public static class StaticRandom
{
private static int seed;
private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
(() => new Random(Interlocked.Increment(ref seed)));
static StaticRandom()
{
seed = Environment.TickCount;
}
public static Random Instance { get { return threadLocal.Value; } }
}
Run Code Online (Sandbox Code Playgroud)
然后你可以随时使用StaticRandom.Instance你需要的实例Random.
现在回到最初的问题,目前的扩展方法正在做什么并不完全清楚.你为什么一直在使用DateTime.Today?我怀疑你想要的东西:
public static DateTimeOffset Random(this DateTimeOffset value, TimeSpan timeSpan)
{
double seconds = timeSpan.TotalSeconds * StaticRandom.Instance.NextDouble();
// Alternatively: return value.AddSeconds(-seconds);
TimeSpan span = TimeSpan.FromSeconds(seconds);
return value - span;
}
Run Code Online (Sandbox Code Playgroud)
然而,这将给你一个完全随机的时间 - 例如,它几乎必然会在一毫秒之内.这没关系,或者你有效地希望它是基于原始时间跨度的精确秒数(或分钟,或小时)?
使用Random一个创建/初始化对象一次,并不会在每次方法被调用的时间.另一种选择是Random在调用它时将实例传递给方法.
您还可以创建允许您执行上述任一选项的重载:
public static DateTimeOffset Random(this DateTimeOffset value, TimeSpan timeSpan)
{
if (_threadStaticRng == null)
_threadStaticRng = new Random();
return value.Random(timeSpan, _threadStaticRng);
}
public static DateTimeOffset Random(
this DateTimeOffset value, TimeSpan timeSpan, Random rng)
{
DateTimeOffset minDateTime = value.Subtract(timeSpan);
int range = ((DateTime.Today - minDateTime)).Hours;
return minDateTime.AddHours(rng.Next(range));
}
[ThreadStatic]
private static Random _threadStaticRng;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4967 次 |
| 最近记录: |