2

鉴于以下

class MyClass
{
    private Expression<Func<SomeEntity, int>> _orderBy;

    public MyClass(Expression<Func<SomeEntity, int>> orderBy)
    {
        _orderBy = orderBy;
    }

    public List<SomeEntity> Fetch()
    {
        return DbContext.Set<SomeEntity>().OrderBy(_orderBy).ToList();
    }
}

// A function that creates an orderBy expression
Expression<Func<SomeEntity, int>> SomeFunction()
{
    // r is a local variable for the sake of simplicity,
    // actually it is a global static variable.
    Random r = new Random();
    int seed = r.nextInt();

    // s.SomeProperty XOR seed, a simple random sorting method
    return s => (s.SomeProperty & ~seed) | (~s.SomeProperty & seed);
}

和执行代码

var myClass = new MyClass( SomeFunction() );

List<SomeEntity> someList = myClass.Fetch();
Thread.Sleep(100000);
List<SomeEntity> anotherList = myClass.Fetch();

每次调用 Fetch() 时,都必须返回一个随机排序的列表。问题是,seed = r.nextInt()每次我调用 Fetch() 时都不会被调用。如何确保每次Fetch()调用时都会生成一个新种子?

4

5 回答 5

2

只需将对 r.Next() 的调用移动到您的委托中。下面的代码(因为我不想实际订购任何东西,所以从您的代码中有点笨拙)每次返回不同的数字。很抱歉变量名很差...

仅供参考,变量r从方法中提升SomeFunction()到堆上,并且会在 Expression> 被调用的任何时候保留并使用。有关闭包的更多信息,请参阅此问题和答案中的链接。

编辑:我已经将随机数生成移到它自己的类中,这似乎可以工作......

internal class MyClass {
    private Expression<Func<string, int>> _aProperty;

    public MyClass(Expression<Func<string, int>> aProperty) {
        _aProperty = aProperty;
    }

    public int Fetch() {
        var something = _aProperty.Compile();
        return something("doesn't matter");
    }
}

public class DoubleUp {
    private Random r = new Random();
    private int currentValue;
    public int A { get { return currentValue; } }
    public int B { get { int tmp = currentValue; currentValue = r.Next(); return tmp; } }

    public DoubleUp() {
        currentValue = r.Next();
    }
}

internal class Program {

    private static Expression<Func<string, int>> SomeFunction() {
        DoubleUp d = new DoubleUp();
        return s => (d.A - d.B);
    }

    private static void Main(string[] args) {
        var myClass = new MyClass(SomeFunction());
        Console.WriteLine(myClass.Fetch());
        Console.WriteLine(myClass.Fetch());
        Console.WriteLine(myClass.Fetch());
        Console.ReadLine();
    }
}
于 2013-08-14T17:57:55.793 回答
0

将表达式设为 Func,每次调用 Fetch 时调用它来获取新的 Orderby:

class MyClass
{
    private Func<Expression<Func<SomeEntity, int>>> _orderByFactory;

    public MyClass(Func<Expression<Func<SomeEntity, int>>> orderByFactory)
    {
        _orderByFactory = orderByFactory;
    }

    public List<SomeEntity> Fetch()
    {
       var orderBy = _orderByFactory();
       return DbContext.Set<SomeEntity>().OrderBy(orderBy).ToList();
    }
}

电话变成了

var myClass = new MyClass( () => SomeFunction() );
List<SomeEntity> someList = myClass.Fetch();
于 2013-08-14T18:08:55.047 回答
0

问题是你只调用SomeFunction一次来设置种子。而且您不能在表达式中重置种子,因为表达式不能包含函数体。

另一种方法是使用 4 个字节的新 Guid 作为伪随机数生成器:

// A function that creates an orderBy expression
Expression<Func<int, int>> SomeFunction()
{
    // Take 4 bytes from a new Guid and turn it into a 32-bit integer
    return s=> BitConverter.ToInt32(Guid.NewGuid().ToByteArray(),0);
}
于 2013-08-14T18:09:19.293 回答
0

鉴于您的问题陈述:

每次调用 Fetch() 时,都必须返回一个随机排序的列表。

在我看来,你是在想太多事情。为什么你不只是做一些简单的事情,比如:

class MyClass
{
  private static Random rng = new Random() ;

  public List<SomeEntity> Fetch()
  {
    return DbContext.Set<SomeEntity>()
                    .Cast<SomeEntity>()
                    .OrderBy( x => rng.Next() )
                    .ToList()
                    ;
  }

}
于 2013-08-14T18:22:49.723 回答
0

一种可能的解决方案是传入一个工厂函数,该函数通过函数而不是函数本身生成订单,现在它每次使用新种子Expression<Func<SomeEntity, int>>调用每个函数时都会生成一个新的。Fetch()

class MyClass
{
    Func<Expression<Func<SomeEntity, int>>> _orderByFactory;

    public MyClass(Func<Expression<Func<SomeEntity, int>>> orderByFactory)
    {
        _orderByFactory = orderByFactory;
    }


    public List<SomeEntity> Fetch()
    {
        var orderBy = _orderByFactory();

        return DbContext.Set<SomeEntity>().OrderBy(orderBy).ToList();
    }
}

//...

// Moved r out of the function as it needs to be outside for it to work.
static Random r = new Random();

static Expression<Func<SomeEntity, int>> SomeFunction()
{
    int seed = r.Next();

    // s.SomeProperty XOR seed, a simple random sorting method
    return s => (s.SomeProperty & ~seed) | (~s.SomeProperty & seed);
}

//...

var myClass = new MyClass(SomeFunction); //<--Notice the removed parenthesis
List<SomeEntity> someList = myClass.Fetch();
Thread.Sleep(100000);
List<SomeEntity> anotherList = myClass.Fetch();
于 2013-08-14T17:50:43.700 回答