zoukankan      html  css  js  c++  java
  • 说说.net cf 2.0 及 3.5 上的 LINQ TO SQL

       我们知道的在.net cf 2.0上没有对LINQ的支持,在.net cf 3.5上即使支持Linq To DataSet和Linq To XML,也还是没有Linq To SQL,在可能即将发布的.net cf 4.0中,好像也没提到Linq To SQL什么事儿,那么是不是基于.net cf 的开发就与Linq To SQL无缘呢?!基实也不尽然。
         在前天我写过一篇《在 .NET 2.0上使用“LINQ”》中,提到通过移植mono代码,在.net 2.0上实现LINQ,那么能不能把它也移植到.net cf上哪?说干就干,跟随我一起来一次“冒险”吧!
    第一关:Reflection.Emit
        在.net cf 2.0 及 3.5上,没有Reflection.Emit相关类库,然而,LINQ Expression的Compile离可它就玩不转了。不过,很幸运地,我们可以找到个EmitCF项目,它基本上实现了Linq Expression用到的功能,第一关算过了。
    第二关:GetCurrentMethod
        精简版就是精简版,经常会碰到函数缺失,多数比较简单的函数基本可以自已实现,可是,一但碰到“内核级”的函数,本人就无能为力了,不可硬攻,就来点“旁门左道”,网上比较流行的方法是通过在Stack中查找最近一次函数调用,可是这种方法无法区分同名的函数,我们不能用,又经过一通琢磨,我发现可以通过函数参数名来区分不同的函数,这一关也过了。

            private static Dictionary<string, Dictionary<string, MethodInfo>> methods = null;
    
            private static void InitializeMethods()
    
            {
    
                methods = new Dictionary<string, Dictionary<string, MethodInfo>>();
    
                MethodInfo[] methodInfoArray = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public);
    
                foreach (var methodInfo in methodInfoArray)
    
                {
    
                    string methodName = methodInfo.Name;
    
                    if (!methods.ContainsKey(methodName))
    
                    {
    
                        methods.Add(methodName, new Dictionary<string, MethodInfo>());
    
                    }
    
                    Dictionary<string, MethodInfo> methodDictionary = methods[methodName];
    
                    string[] parameterNames = GetParameterNames(methodInfo);
    
                    string parameterNameKey = string.Join(",", parameterNames);
    
                    if (!methodDictionary.ContainsKey(parameterNameKey))
    
                    {
    
                        methodDictionary.Add(parameterNameKey, methodInfo);
    
                    }
    
                }
    
            }
    
    
    
            private static string[] GetParameterNames(MethodInfo methodInfo)
    
            {
    
                if (methodInfo.IsGenericMethodDefinition)
    
                {
    
                    System.Type[] genericArguments = methodInfo.GetGenericArguments();
    
                    System.Type[] types = new System.Type[genericArguments.Length];
    
                    for (int i = 0; i < types.Length; i++)
    
                    {
    
                        types[i] = typeof(int);
    
                    }
    
                    methodInfo = methodInfo.MakeGenericMethod(types);
    
                }
    
                ParameterInfo[] parameterInfoArray = methodInfo.GetParameters();
    
                string[] parameterNames = new string[parameterInfoArray.Length];
    
                for (int i = 0; i < parameterInfoArray.Length; i++)
    
                {
    
                    parameterNames[i] = parameterInfoArray[i].Name;
    
                }
    
                return parameterNames;
    
            }
    
    
    
            private static MethodBase GetCurrentMethod(string methodName, string[] parameterNames)
    
            {
    
                if (methods == null)
    
                {
    
                    InitializeMethods();
    
                }
    
                if (methods.ContainsKey(methodName))
    
                {
    
                    Dictionary<string, MethodInfo> methodDictionary = methods[methodName];
    
                    string parameterNameKey = string.Join(",", parameterNames);
    
                    if (methodDictionary.ContainsKey(parameterNameKey))
    
                    {
    
                        return methodDictionary[parameterNameKey];
    
                    }
    
                }
    
                return null;
    
            }
    

    第三关:inner class
        前面提到的EmitCF有个问题,因为它生成独立的程序集来执行Emit的动态代码,而Linq表达式内的支匿名对象又被编译成inner类型,这样EmitCF生成的动态代码就访问不到这些对象,这种情况下我们通过会第一时间想到"反射",那我们就用Emit生成反射调用代码来访问这些对象,调试起来确实麻烦了许多,不过终归还是执行过去了。
    第四关:DbLinq
      说到这儿,离LINQ TO SQL很近了,但也不就说,这样就很容易现实,因为我想移植DbLinq过程中可能还会碰到更多问题,很遗憾我没机会走下去了,因为我最初的目的是要完成.net cf 上的"Linq to DAC",我的想法基本上实现了,虽然还有些问题(见注1),但今天也就到这儿了。

            [Test]
            public void TestMethod1()
            {
                QueryableData<Issue> issues = new QueryableData<Issue>(dc);
                 var il = from s in issues where s.IssueID > 0 && s.Title == "a" select s;
                foreach (var i in il)
                {
                    Assert.IsTrue(i.IssueID > 0);
                    Assert.IsTrue(i.Title == "a");
                }
            }
    
    


    注1:
    1. 动态程序集没法的内存中直接加载,一定要生成物理文件。
    2. 在Linq表达式中,不能使用数组的元素作为数据值,如:s.IssueID == issueList[0], 会出错。
    3. 不能使用select new {...} 返回新的动态对象。

  • 相关阅读:
    想当老板的人,三点特征很重要(转)
    突破三个自我,你就不光是老板的料
    掌握这3套创业战略 保你赚到百万财富 
    也感山西黑窑洞
    再游府河有感
    朋友的影响力非常大,朋友决定你的财富
    夏日乘凉
    职业生涯的八大“定位法则”
    一生何求
    赠你一方明月
  • 原文地址:https://www.cnblogs.com/zhongzf/p/1709523.html
Copyright © 2011-2022 走看看