在Expression中包含一个Method类

时间:2013-08-14 17:30:34

标签: .net linq entity-framework lambda

鉴于以下内容

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

5 个答案:

答案 0 :(得分:2)

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

仅供参考,变量r从方法SomeFunction()升级到堆上,并且会在任何时候使用Expression&gt;被叫。有关闭包的更多信息,请参阅This question and the link in the answer

编辑:我已将随机数生成移动到自己的类似乎有效......

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();
    }
}

答案 1 :(得分:0)

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

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();

答案 2 :(得分:0)

使表达式成为每次调用Fetch时调用以获取新Orderby的Func:

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();

答案 3 :(得分:0)

问题是您只需拨打SomeFunction一次即可设置种子。并且您无法在Expression中重置种子,因为表达式不能包含函数体。

另一种方法是使用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);
}

答案 4 :(得分: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()
                    ;
  }

}