创建可用作Func /方法的类型 [英] Creating a type that can be used as a Func/method

查看:203
本文介绍了创建可用作Func /方法的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在玩 LINQ to Z3 的乐趣(不是生产使用)。

I have been playing around with LINQ to Z3 for fun (not production use).

我已经结束了这种语法作为开始:

I've ended up with this syntax as a start:

var i = 123;
var test2 = from t in TheormProver.NewTheorm()
            let f = TheormProver.Func<int, bool>()
            let a = TheormProver.Int
            let g = TheormProver.Func<bool, int>()
            where !f(a * 2) && g(f(g(f(4)))) == i * a && a < g(f(a))
            select new { f = f.ToString(), g = g.ToString(), a, asd = "Test extra property" };

var solution = test2.Solve(); // Edited in for clarification
// note that test2 is a TheormProver<T> which has a "T Solve()" method defined.

静态 TheromProver.Int TheormProver.Func methods / properties只返回一个基本类型(根据他们的名字)。

The static TheromProver.Int and TheormProver.Func methods/properties simply return a basic type (as per their name) currently.

向前移动我想做一个变量< T> 类型,其中包含的信息不仅仅是一个值。

Moving forwards I want to make a sort of Variable<T> type that contains more information than just a value.

TL ; DR:我遇到的问题是我想要 f g 变量为我可以添加字段和属性的自定义类型,我仍然希望能够使用where语句中的where语句(即作为方法/ Func )。

TL;DR: The problem I'm having is that I want f and g variables to be a custom type that I can add fields and properties to, but I still want to be able to use them with the syntax I've got in the where clause (i.e. as a method/Func).

所以,如何创建一个可以在方法语法中使用的自定义类型,同时添加/自己的属性?

请注意,我不在乎如果调用该方法什么也不做,或者不工作,因为我将操纵where子句所以他们永远不会被调用/执行。

Note that I don't care if calling the method does nothing, or doesn't work as I'll be manipulating the where clause so they'll never get invoked/executed.

示例:

var test2 = from t in TheormProver.NewTheorm()
            let f = TheormProver.Func<int, bool>()
            let a = TheormProver.Int
            where !f(a * 2) && a > 3 // f is used to create a method call expression
            select new { f , a };

var testSolution = test2.Solve();

var fSolution = testSolution.f; // F is its own type with unique properties/fields.

var fConstraints = fSolution.Constraints;

var fSomeProperty = fSolution.SomeProperty;

foreach(var constraint in fConstraints)
{
    //.....
}

我已经嘲笑了我迄今为止所进行的语法工作的一个简单例子:

I've mocked up a quick example of the work in progress syntax I have so far:

< a href =http://liveworkspace.org/code/3Fm6JM%240 =nofollow> http://liveworkspace.org/code/3Fm6JM$0

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class TheormProver
    {
        public static int Int { get { return default(int); } } // Really this would return my Variable<int>
        public static Func<T, TResult> Func<T, TResult>() { return default(Func<T, TResult>); } // Really this would return my Variable<Func<T, TResult>>

        protected List<Expression> Constraints; // Holds constraints / where clauses that get translated into the Z3 language

        //This gets called when we do the first "let" and gets us into the correctly typed world with a generic parameter
        public virtual TheormProver<T> Select<T>(Func<TheormProver, T> sel)
        {
            return new TheormProver<T>(Constraints);
        }
    }

    // This is what the user of the library sees and is returned by a from t in new TheormProver(). T will be the anonymous type from the last let
    class TheormProver<T> : TheormProver
    {
        public TheormProver(List<Expression> Constraints)
        {

        }

        // This gets called on subsequent "let"s, going from the anonymous type with one property "f" to one with 2, "f, g". Chaining this way allows as many lets as we want
        public virtual TheormProver<U> Select<U>(Expression<Func<T, U>> sel)
        {
            return new TheormProver<T, U>(sel, Constraints.ToList());
        }

        public virtual TheormProver<T> Where(Expression<Func<T, bool>> constraint)
        {
            var result = (TheormProver<T>)this; // This should be a clone to allow composable queries

            result.Constraints.Add(constraint);

            return result;
        }

        public virtual T Solve(out bool foundSolution)
        {
            // TODO: Call Z3 and get a solution
            foundSolution = false;
            return default(T);
        }
    }

    internal class TheormProver<T, U> : TheormProver<U>
    {
        private LambdaExpression Selector;
        private TheormProver<T> InternalTheorumProver;

        public TheormProver(Expression<Func<T, U>> selector, List<Expression> constraints)
            : base(constraints)
        {
            Selector = selector;
            InternalTheorumProver = new TheormProver<T>(constraints);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var test = from t in new TheormProver()
                       let f = TheormProver.Func<int, bool>()
                       let g = TheormProver.Func<bool, int>()
                       let a = TheormProver.Int
                       where g(f(a)) == 0
                       select new { f, g, a };

            bool foundSolution;
            var testSolution = test.Solve(out foundSolution);
        }
    }
}


推荐答案

我为您的原始代码创建了一个简单的testbed: http://liveworkspace.org / code / 3Bl7wC $ 0

I've created a simple 'testbed' for your original code: http://liveworkspace.org/code/3Bl7wC$0.

有了一点动态的魔法,你可以把下面的类替换为$ code> Func< T1,T2> :

With, a bit of dynamic magic, you can have the following class as a drop-in replacement for Func<T1, T2>:

public class MyCallable<T1, T2> : DynamicObject
{
    private readonly Expression<Func<T1, T2> > _wrapped;
    private readonly Func<T1, T2> _compiled;

    public MyCallable(Expression<Func<T1, T2>> towrap) 
    { 
        _wrapped = towrap; _compiled = _wrapped.Compile(); 
    }

    public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
    {
        if ( (args.Length == 1) && 
             (args[0].GetType() == typeof(T1)))
        {
            Console.WriteLine(@"Invoking ""{0}"" on {1}", _wrapped, args[0]);
            result = _compiled((T1) args[0]);
            return true;
        }
        else
        {
            //throw new ArgumentException("Cannot invoke " + _wrapped + " with the arguments passed");
            result = null;
            return false;
        }
    }
}

如你所见,它将您的类定义为动态,并允许您尝试并调用它,就像它是一个代表/函数/ ...一般调用:

As you can see, it defines you class as being "dynamic" and allows you to try and invoke it as if it were a delegate/function/... a general callable:

// in "TheormProver"
public static dynamic Func<T1, T2>() { return new MyCallable<T1, T2>(arg1 => default(T2)); }

这是证明它的作品: http://liveworkspace.org/code/4kBypd$0

Here's proof it works: http://liveworkspace.org/code/4kBypd$0

输出:

Output:

Invoking "arg1 => False" on 0
Invoking "arg1 => False" on 4
Invoking "arg1 => 0" on False
Invoking "arg1 => False" on 0
Invoking "arg1 => 0" on False
Invoking "arg1 => False" on 0
Invoking "arg1 => 0" on False

参考:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Dynamic;

public class Program
{
    public class MyCallable<T1, T2> : DynamicObject
    {
        private readonly Expression<Func<T1, T2> > _wrapped;
        private readonly Func<T1, T2> _compiled;

        public MyCallable(Expression<Func<T1, T2>> towrap) 
        { 
            _wrapped = towrap; _compiled = _wrapped.Compile(); 
        }

        public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
        {
            if ( (args.Length == 1) && 
                 (args[0].GetType() == typeof(T1)))
            {
                Console.WriteLine(@"Invoking ""{0}"" on {1}", _wrapped, args[0]);
                result = _compiled((T1) args[0]);
                return true;
            }
            else
            {
                //throw new ArgumentException("Cannot invoke " + _wrapped + " with the arguments passed");
                result = null;
                return false;
            }
        }
    }

    public static class TheormProver
    {
        public static object[] NewTheorm() { return new object[] { 1 }; }
        public static dynamic Func<T1, T2>() { return new MyCallable<T1, T2>(arg1 => default(T2)); }
        public static int Int { get; set; }
    }

    public static void Main(string[] args)
    {
        var i = 123;
        var test2 = from t in TheormProver.NewTheorm()
            let f = TheormProver.Func<int, bool>()
            let a = TheormProver.Int
            let g = TheormProver.Func<bool, int>()
            where !f(a * 2) && g(f(g(f(4)))) == i * a && a < g(f(a))
            select new { f = f.ToString(), g = g.ToString(), a, asd = "Test extra property" };

        test2.ToList().ForEach(Console.WriteLine);
    }

}

这篇关于创建可用作Func /方法的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆