xml地图|网站地图|网站标签 [设为首页] [加入收藏]
应用开发之Linq和EF,NET的反射特性
分类:编程

     在.net框架体系内,反射特性较多的应用到。反射的相关定义分为两种。

本章简言

(1)使用=直接赋值

     自然解释:射是一种自然现象,表现为受刺激物对刺激物的逆反应;这是反射的字面解释,我们看一下计算机编程中的反射;

上一章笔者对于WinForm开发过程用到的几个知识点做了讲解。笔者们可以以此为开端进行学习。而本章我们来讲一个跟ORM思想有关的知识点。在讲之前让我们想一下关于JAVA的hibernate知识点。hibernate也是ORM框架。记得hibernate里面有一个叫HQL。先不管HQL的好与坏。主要是明白HQL的目地是什么。ORM的思想就是为了让用户在操作数据的时候用上面向对象的思想来看,而不是二维数据了。所以HQL笔者认为就是一个面向对象思想的SQL语句。那么为什么笔者要讲到HQL呢?事实上笔者认为Linq有一点跟他类似。如果项目架构是三层的话,就是让业务层的开发人员不用在看二维数据了。就连SQL语句都是面向对象思想形式来操作了。而EF(Entity Framework)可以说就是hibernate。即是可以理解为Linq的数据源。但是HQL要在hibernate上面才能有效果。Linq却可以不用EF。

a = [1, 2, 3, [6, 7]]

     编程解释:通过 System.Reflection 命名空间中的类以及 System.Type,您可以获取有关已加载的程序集和在其中定义的类型(如类、接口和值类型)的信息。 您也可以使用反射在运行时创建类型实例,以及调用和访问这些实。

Linq语法

b = a

     反射(Reflection)有下列用途:它允许在运行时查看属性(attribute)信息;它允许审查集合中的各种类型,以及实例化这些类型;它允许延迟绑定的方法和属性(property);它允许在运行时创建新类型,然后使用这些类型执行一些任务。

.NET对于Linq知识的分类让笔者有时候觉得很无力。为什么呢?最早的时候笔者认为Linq知识点分三大块。分别为Linq to SQL、Linq to Entity、Linq to Database。随着对Linq使用的增加却发现还有Linq to Xml 、Linq to Excel等。笔者想读者们是不是看出门道来了。可以说.NET在设计Linq的时候,应该是有充分的想过将来扩展的问题。当然这不是本章的目标。笔者在开发过程中最常用的就是Linq to SQL和 Linq to Entity。另外还有一个叫Linq to Object.对于Linq to Object笔者一直认为就是Linq to Entity。笔者的意思是指他们的知识该应放在一块。好了。先笔者讲一下关于Linq to SQL。

 

     下面介绍一下有关反射的程序集的相关属性和方法的源码:

对于Linq to SQL来讲,只要学习SQL语法的人都不用担心很容易就上手。记得笔者学习的时候,一看我去不就HQL的另一种形态吗?当然 HQL可不是Linq还是要学习一下的。讲那么多没有用。用列子才是最好的。

初始情况:

        (1).Object的GetType()方法:

一、建立EF环境。先建一个项目,然后通过NUGET来获得对应的EF的DLL。对于NUGET是什么。相信看过《Java进击C#——项目开发环境》的人应该可以了解到。选择“引用”右击》管理Nuget程序包。

a: [1, 2, 3, [6, 7]]

    // Returns a Type object which represent this object instance.
    // 
    [System.Security.SecuritySafeCritical]  // auto-generated
    [Pure]
    [ResourceExposure(ResourceScope.None)]
    [MethodImplAttribute(MethodImplOptions.InternalCall)]
    public extern Type GetType();

图片 1

b: [1, 2, 3, [6, 7]]

      (2).PropertyInfo的GetProperty()方法:

相信看了上面的图片的时候,我们已经发现了EntityFramework了吧。点击“安装”就可以了。这个时候项目就会多出一个叫packages.config文件。这里面记录着当前安装的dll信息。同时物理目录里面会多出一个文件夹packages来存在这些dll。


 public PropertyInfo GetProperty(String name,BindingFlags bindingAttr,Binder binder, 
                        Type returnType, Type[] types, ParameterModifier[] modifiers)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            if (types == null)
                throw new ArgumentNullException("types");
            Contract.EndContractBlock();
            return GetPropertyImpl(name,bindingAttr,binder,returnType,types,modifiers);
        }

        public PropertyInfo GetProperty(String name, Type returnType, Type[] types,ParameterModifier[] modifiers)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            if (types == null)
                throw new ArgumentNullException("types");
            Contract.EndContractBlock();
            return GetPropertyImpl(name,Type.DefaultLookup,null,returnType,types,modifiers);
        }

        public PropertyInfo GetProperty(String name, BindingFlags bindingAttr)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            Contract.EndContractBlock();
            return GetPropertyImpl(name,bindingAttr,null,null,null,null);
        }

        public PropertyInfo GetProperty(String name, Type returnType, Type[] types)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            if (types == null)
                throw new ArgumentNullException("types");
            Contract.EndContractBlock();
            return GetPropertyImpl(name,Type.DefaultLookup,null,returnType,types,null);
        }

        public PropertyInfo GetProperty(String name, Type[] types)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            if (types == null)
                throw new ArgumentNullException("types");
            Contract.EndContractBlock();
            return GetPropertyImpl(name,Type.DefaultLookup,null,null,types,null);
        }

        public PropertyInfo GetProperty(String name, Type returnType)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            if (returnType == null)
                throw new ArgumentNullException("returnType");
            Contract.EndContractBlock();
            return GetPropertyImpl(name,Type.DefaultLookup,null,returnType,null,null);
        }

        internal PropertyInfo GetProperty(String name, BindingFlags bindingAttr, Type returnType)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            if (returnType == null)
                throw new ArgumentNullException("returnType");
            Contract.EndContractBlock();
            return GetPropertyImpl(name, bindingAttr, null, returnType, null, null);
        }

        public PropertyInfo GetProperty(String name)
        {
            if (name == null)
                throw new ArgumentNullException("name");
            Contract.EndContractBlock();
            return GetPropertyImpl(name,Type.DefaultLookup,null,null,null,null);
        }

图片 2

修改a[1] = 5之后的情况

   (3).Object的GetValue()方法:

我们看到引用里面多出了关于EF的引用dll。这个时候我们就可以做EF的事情了。

a: [1, 5, 3, [6, 7]]

[DebuggerStepThroughAttribute]
        [Diagnostics.DebuggerHidden]
        public Object GetValue(Object obj)
        {
            return GetValue(obj, null);
        }

        [DebuggerStepThroughAttribute]
        [Diagnostics.DebuggerHidden]
        public virtual Object GetValue(Object obj,Object[] index)
        {
            return GetValue(obj, BindingFlags.Default, null, index, null);
        }

        public abstract Object GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture);

二、新建EF上下文。EF有一个很重要的类。可以说是学习EF的核心点。这个类就是DbContext。笔者新建一类叫AomiContext继承他。如下

b: [1, 5, 3, [6, 7]]

  以上介绍了一下有关反射的相关方法的底层方法源码,现在介绍一下较为通用的方法:

public class AomiContext : DbContext
{

}

    (1).获取对象的所有公共属性。

DbContext类有几个构造函数。笔者这里讲一个常用的吧。如下

修改b[2] = 8之后的情况

        /// <summary>
        /// 获取对象的所有公共属性。
        /// </summary>
        /// <param name="obj">定义该方法的数据类型。</param>
        /// <returns>返回包含该对象的属性信息的数组。</returns>
        public static IEnumerable<PropertyInfo> GetProperties(this object obj)
        {
            return obj.GetType().GetProperties();
        }
 public DbContext(string nameOrConnectionString);

a: [1, 5, 8, [6, 7]]

    (2).获取一个对象的属性。

就是个构造函数意思就是传一个连接字符串或是配置文件的连接字符的配置名。记得上一节中讲的App.config了吧。没有错就是要用到他。看一下笔者写的内容吧。

b: [1, 5, 8, [6, 7]]

        /// <summary>
        ///获取一个对象的属性。
        /// </summary>
        /// <param name="obj">定义该方法的数据类型。gb</param>
        /// <param name="flags">提供要确定要检索的属性的标志。</param>
        /// <returns>返回包含该对象的属性信息的数组。</returns>
        public static IEnumerable<PropertyInfo> GetProperties(this object obj, BindingFlags flags)
        {
            return obj.GetType().GetProperties(flags);
        }
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <connectionStrings>
    <add name="aomi" connectionString="Data Source=.;Initial Catalog=Ado;Persist Security Info=True;User ID=sa;Password=123" providerName="System.Data.SqlClient"/>
  </connectionStrings>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

    (3).用指定名称获取具有指定名称的属性的当前对象的属性值。

上面的connectionStrings部分是笔者自己写的。其他是自动生成的。.NET自己有一个配置连接字符串的节点。我们就是在这个节点上写入自己的连接就可以了。

修改a[3][0] = 10之后的情况

        /// <summary>
        ///用指定名称获取具有指定名称的属性的当前对象的属性值。
        /// </summary>
        /// <param name="obj">要检索的属性值的对象。</param>
        /// <param name="propertyName">要检索的属性的名称。</param>
        /// <returns>返回属性的值。</returns>
        public static object GetPropertyValue(this object obj, string propertyName)
        {
            var item = obj.GetType().GetProperty(propertyName);

            if (item == null) return null;
            var value = obj.GetType().GetProperty(propertyName).GetValue(obj);

            if (item.PropertyType.IsGenericType)
            {
                value = item.PropertyType.GetProperty(propertyName);
            }
            return value;
        }
<add name="aomi" connectionString="Data Source=.;Initial Catalog=Ado;Persist Security Info=True;User ID=sa;Password=123" providerName="System.Data.SqlClient"/>

a: [1, 5, 8, [10, 7]]

     (4).获取一个枚举字符串值。

好了。接下来就是把AomiContext类修改一下。让他跟对应的连接字符串的配置发生关系。如下

b: [1, 5, 8, [10, 7]]

        /// <summary>
        ///获取一个枚举字符串值。
        /// </summary>
        /// <param name="obj">该枚举返回的字符串值。</param>
        /// <returns>返回一个枚举字符串值。</returns>
        public static string GetStringValue(this System.Enum obj)
        {
            var fieldInfo = obj.GetType().GetField(obj.ToString());
            var attributes = fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];

            var output = (StringValueAttribute)attributes.GetValue(0);

            return output.Text;
        }
 public class AomiContext : DbContext
    {
        public AomiContext()
            : base("Aomi")
        { }
    }

     (5).获取方法调用。

看到红色部分的代码了吧。把Aomi就是对应上面配置add节点的name的值。这个时候EF会自己去配置文件里面去找。

修改b[3][0] = 20之后的情况

        /// <summary>
        /// 获取方法调用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="action"></param>
        /// <returns></returns>
        public static MethodCallExpression GetMethodCall<T>(Expression<T>  action )
        {
            var call = action.Body as MethodCallExpression;

            return call;
        }

三、建立表和类的映射。

a: [1, 5, 8, [20, 7]]

    (6).获取类型名称.

对应数据库的表:

b: [1, 5, 8, [20, 7]]

        /// <summary>
        /// 获取类型名称
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static string GetTypeName<T>()
        {
            return typeof (T).Name;
        }
CREATE TABLE [dbo].[Catalogs](
    [ID] [int] NOT NULL,
    [CatalogName] [nvarchar](50) NULL,
    [CatalogCode] [nvarchar](50) NULL,
 CONSTRAINT [PK_Catalogs] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

    (7).获取参数值

对应数据库的数据

 

        /// <summary>
        /// 获取参数值
        /// </summary>
        /// <param name="methodCall"></param>
        /// <returns></returns>
        public static IEnumerable<Tuple<ParameterInfo, object>> GetArgumentValues(MethodCallExpression methodCall)
        {
            var parameters = methodCall.Method.GetParameters();
            if (!parameters.Any()) yield break;
            for(var i = 0; i < parameters.Length; i++)
            {
                var arg = methodCall.Arguments[i];

                var ceValue = arg as ConstantExpression;

                if (ceValue != null)
                    yield return new Tuple<ParameterInfo, object>(parameters[i], ceValue.Value);
                else
                    yield return new Tuple<ParameterInfo, object>(parameters[i], GetExpressionValue(arg));
            }
        }
INSERT [dbo].[Catalogs] ([ID], [CatalogName], [CatalogCode]) VALUES (1, N'小吃', N'c0001')
INSERT [dbo].[Catalogs] ([ID], [CatalogName], [CatalogCode]) VALUES (2, N'计算机', N'c0002')

此时我理解中的内存图如下所示(0x0012xx表示内存地址):

    (8).获取表达式值

笔者建一个类用于跟数据库里面的表相对应。这个时候要记得属性要跟表里里面的列名一样子才行。代码如下

 图片 3

        /// <summary>
        /// 获取表达式值
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        private static object GetExpressionValue(Expression expression)
        {
            var lambda = Expression.Lambda<Func<object>>(Expression.Convert(expression, typeof (object)));
            var func = lambda.Compile();
            return func();
        }
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqExample
{
    public class Catalogs
    {
        public int ID { set; get; }

        public string CatalogName { set; get; }

        public string CatalogCode { set; get; }
    }
}

 

    反射类的继承层次如下:

有了对应的类之后,还不行。我们还要修改一下AomiContext类。这样子就可以通过AomiContext类来访问对应的类对象了。即是数据了。如下

即:使用=直接赋值,是引用赋值,更改任何其中一个,另一个都会改变。可以理解为:将列表a的指针赋值给b,此时a,b共用一个内存空间。

      System.reflection  

    public class AomiContext : DbContext
    {
        public AomiContext()
            : base("Aomi")
        { }

        public IDbSet<Catalogs> Catalogs { set; get; }
    }

 

本文由澳门新葡亰手机版发布于编程,转载请注明出处:应用开发之Linq和EF,NET的反射特性

上一篇:Python2中文处理纪要,Django思维导图 下一篇:很具体很用实用,批量自动重命名音乐文件
猜你喜欢
热门排行
精彩图文