乘势社会的发展,游戏产业渐渐升温,各大娱乐集团赚得盆满钵盈,例如国内游戏产业龙头老大腾讯,在发布了前年第一季度财报中,Q1总收入495.52亿,同比提升55%,其中网络游戏收入达到228.11亿,同比增长34%。游戏收入占总收入的46%。

  .NET中的LINQ对于操作集合对象提供了许多的有益,使得我们可以在C#中利用类似于SQL语句的办法对聚集中的对象开展检索、分组、总括等。使用LINQ写出来的代码简单明了,省去了俺们原来需要使用大量for循环或者foreach循环才能落实的机能。众所周知,通过LINQ查询所重临的结果一般的话是一个以var所标识的匿名类型,该类型继承自IEnumerable接口,我们可以直接将它绑定到任何一个数据绑定控件,如DropDownList,ListBox,DataGridView等。但这里有一个题材,对于DataGridView(WinForm版)来说,如若应用LINQ重临的匿名对象举办数据绑定的话,会失去DataGridView中单击列标题举行数量排序的效力,这是因为DataGridView不可能从一个匿名对象中拿走到展开数据排序的切实可行规则。要解决这一个题材,你可以给这一个匿名对象编排具体的排序算法,不过最简易的做法依然将以此匿名对象转换成我们所熟练的集纳对象,如DataTable,然后再绑定到DataGridView中。

此外,据腾讯发表的稿子《2017中华互联网趋势报告:游戏单位时长变现成效高》中,中国在2016年跨越美利坚联邦合众国,成为中外第一大游戏市场,全国游戏市场获益将近250亿比索。数据如图一所示。

  查找msdn,你可以找到将LINQ to
DataSet的结果转换成DataTable的主意。上边的代码片段来源于msdn上的牵线,http://msdn.microsoft.com/zh-cn/library/bb396189(v=vs.90).aspx

除此以外按照CNNIC发表的第39次《中国互联网络发展总计报告》中显得,截止2016年1三月,我国网络游戏用户规模高达4.17亿,占总体网民的57.0%,较二零一八年增强2556万人。手机网络游戏用户规模较2018年初显明提高,达到3.52亿,较二〇一八年终提升7239万人,占手机网民的50.6%。数据如图二所示。

// Bind the System.Windows.Forms.DataGridView object
// to the System.Windows.Forms.BindingSource object.
dataGridView.DataSource = bindingSource;

透过可以见到,游戏产业是这般地热烈,游戏是这般地令人“沉迷”。

// Fill the DataSet.
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;
FillDataSet(ds);

那么为何游戏会如此受玩家群体的欢迎?我认为能够从动机理论和报告机制进行切磋。

DataTable orders = ds.Tables[“SalesOrderHeader”];

在一部成熟的角色扮演游戏中,有着“完整的升级换代机制”、“明确知晓的成就目标”、“丰裕的自由度”、“完全量化、精确化的上报机制”,
其中“完全量化、精确化的申报机制”尤为重大。
或者说一部成功的游玩完美显示了J·理查德(理查德)·哈尔(Hal)曼的七个着力工作维度:技能的多样性、任务的完整性、任务的机要、工作的自主性、反馈。

// Query the SalesOrderHeader table for orders placed 
// after August 8, 2001.
IEnumerable<DataRow> query =
    from order in orders.AsEnumerable()
    where order.Field<DateTime>(“OrderDate”) > new DateTime(2001, 8, 1)
    select order;

1、全体的提拔机制——清晰的“目标”、可行的“道路”,“人生”不再盲目。“提拔机制”则指的是玩玩中角色的各个指标,例如角色扮演类娱乐的大军值、战斗力、装备性能、角色等级和棋牌类游戏中的胜场、胜率、财产等,它们的增高都坚守一定的正统,一定的总括公式,有序的增进。从某种程度上说,这满意了玩家心情上的“公平”述求。

// Create a table from the query.
DataTable boundTable = query.CopyToDataTable<DataRow>();

           清晰的玩乐“人生”目的                                        
   

// Bind the table to a System.Windows.Forms.BindingSource object, 
// which acts as a proxy for a System.Windows.Forms.DataGridView object.
bindingSource.DataSource = boundTable;

2、数据化的人物属性,助玩家丰硕认识“自己”。据总计,有39.2%的玩家表示偏好“练级”,27.1%的玩家偏好“收集装备”,13.9%的玩家表示偏好“打钱”。所以,玩家的靶子之一就是提色等级上升顶级后,战斗力则改为2000,再配上一件出色的配备,战斗力变为3000,然后花钱买了一件更好的武装,战斗力变为了4000。比较数据前后,可以非凡通晓的相比出战斗力“数据”的出入。而且,在PK
在此以前,玩家仍可以相比较敌方与我方的“数据”差别,大概而高速地相比出差别大小,从而规范判断出胜算程度,然后再做出最合理的“PK”决定。对于玩家来说,那个多少是显然的、及时的、可以掌控的,从而让玩家“完美掌控”其游戏角色的,做到“知己知彼”,与队友“有效联系”,及时作出合理“决策”,更易得到满意感、成就感。

  但是这一个点子不是我们所期待的!原因是其中的泛型类型必须是DataRow而不可以是自定义类型。咋办呢?大家可以仍旧不可以将以此模式修改一下让它能支撑任意档次?

         数据化的人物属性,助玩家充裕认识“自己                          
                 

  还记得从.NET
3.0从头就提供的一个效能吗?C#扩充方法。它同意我们向现有项目中“添加”方法,而无需成立新的派生类型、重新编译或以其他模式修改原始类型。看看msdn上的介绍,先来熟知一下怎么是C#增添方法吧!http://msdn.microsoft.com/zh-cn/library/bb383977.aspx

为此,在“中国网络游戏用户青睐的游乐内外活动”问题的调研中,才会分别有60.1%和51.5的玩家表示喜好“双倍经验”和“增添掉宝和收入”。总括结果如图五所示。

  C#扩充方法是给现有项目“添加”一个主意,现有项目可以是骨干数据类型(如int,string等),也得以是自定义类型。定义规则是增添方法必须定义在一个任意命名的静态类中,该方法必须是静态方法,可以肆意命名,方法的参数列表必须以this关键字先导,第二个即为要增加的数据类型,第两个是一个变量名,同时参数列表中允许定义五个其他参数以贯彻情势的重载。来看一个事例。

3、“充裕多彩的对象,量化进程,成就感爆棚”。通过游戏本身的设定,不同游戏所有不同的“明确知道的完成目标”,例如通关,PK战斗胜利等,那些目的的完结与否,距离成功有多大差距都足以肯定的以数量的款式反映。例如,关卡一共有5关,玩家已经经过了4关,还剩一关没过;玩家在PK
中输给了其他玩家,其角色被其他玩家“制服”,游戏角色死亡,电脑屏幕“黑屏”。再者,游戏创立商往往不会把嬉戏难度设定得太大,否则就是自杀他们后路。

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ‘ ‘, ‘.’, ‘?’ }, 
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }   
}

并且,游戏中还会有各样种排名榜,各类名目,例如排名榜在热点游戏《守望先锋》中有“战力名次榜”第***名,称号在前日最热、最赚钱游戏《英雄联盟》有青铜、白银、黄金、铂金、钻石、大师、最强王者等。这些招数确实会极大地激发大部分玩家的好胜心等“自我实现需求”,再添加游戏创立商有目的在于玩乐中特出“战力”、“称号”的差别,例如不同“称号”或“战力”的玩家所有不同的边框、图标、奖励等,从而玩家会激励出更大的“上进”重力。又因为玩家在名次榜中的排行差异,距离拿到下一个“称号”的距离都是能够了解地以数据的样式显示出来,玩家在这种“完全量化、精确化的上报机制中”及时、准确把握自己的进度,不断拿到“提高”的满意感、成就感。

  静态类MyExtensions被定义在命名空间ExtensionMethods中,静态方法WordCount的参数列表中确定了该办法是对String类型的方法举办了扩张。在实质上采取中,你需要在代码中增长对ExtensionMethods命名空间的引用,然后经过String.WordCount()的点子来调用这一个扩大方法。是不是很神奇啊?再看一个例子。

                   精确化及时报告,准确定位自己,拿到不断提高的“成就感”
                                           

namespace MyExtension
{
    public static class Test    {
        public static XElement ToXml(this DirectoryInfo dir)
        {
            // TO Do Something
        }
    } 
}

故而从得到满意、成就的“自我实现”动机来说,在打闹经过中,无论是从“进度”仍然“结果”,成功更便于把握,因此玩家更易于拿到充足的满足感、成就感

  下面的代码片段对DirectoryInfo类的办法举行了扩张,将上述代码补充完整,便可以直接通过下边的主意调用新扩展的法门。

4、此外,游戏往往拥有“丰富的自由度”。一部成功的游玩所有多种格局,例如团队竞赛,个人竞赛或是剧情格局,PK格局,并且相同种格局下又有两样的玩法。例如团队比赛需要好的协作,配合,那反映了“任务的显要”。还有,基于玩法的多样性,游戏中玩家能够公布团结的想象力,或享受不同的玩法或创办中更多的玩法。这反映了“工作的自主性”和“任务的机要”。

DirectoryInfo dir = new DirectoryInfo(path);
dir.ToXml();

综上说述,人们基于某种“自我实现”目标,在游玩世界中遵守合理的“提拔机制”,同时采用“完全量化、精确化的上报机制”的佑助,动机水平具有更大的“强度”、更显著的“方向性”、更强的“坚定不移性”,从而得到充裕的重力,完美掌控“自己”、完全把握“自我实现”目的的长河,由此拿到极大的知足感、成就感。

  C#增加方法允许对自定义的品类举行扩展,同时同意带参数,协助重载。看下边的例子。

可是当大家相比现实境况来看,假设游戏世界是一个实在存在的世界,则它可以认为是“完全数据化”的现实性。可是真正的世界并不是这种“完美反馈”的“完全数据化”世界。在切实中,人类没法对协调的姣好、身体属性、能力属性等举行完美合理地量化,因而相对游戏来说,我们不可以收获像娱乐中这样及时、准确、量化的反映。所以,人们会日常不知所可,不知底什么样升级自己或者说很难领会自己是不是有升级,自己的全力是否有效。没有顿时得力的上报,就不曾更强的重力。故现实世界对绝大多数人的话很难“沉迷”。

namespace TestExtendMethod
{
    public class Student
    {
        public string Description()
        {
            return “Student………….”;
        }
        public string Description(string name)
        {
            return “the student’s name is ” + name;
        }
    }

实际毕竟是现实,虚妄毕竟是虚妄。现实的繁杂不可以被忽视,人类心思的多样性不能被忽视。人类最有价值的“自我实现”还得是从现实中来。据悉前文对游乐的令人“沉迷”原因的座谈与定论,我们得以看到动机理论和申报机制的巨大效用。那么一定,在切切实实中,它的机能也不会小。成立可行地利用动机理论和上报机制,无疑可以对人类自己管理促进以及团队中员工的田间管理推向有根本的效能。

    public static class Extensions
    {
        public static string TestMethod(this Student s)
        {
            return s.Description();
        }

        public static string TestMethod(this Student s, string name)
统计,        {
            return s.Description(name);
        }
    }
}

  于是,自定义的Student类具有了带有一个重载的TestMethod方法,该措施允许收取一个string类型的参数或者尚未参数。

  好了!回到大家的主旨上来。既然C#扩展方法允许我们对项目充分方法,那么我们完全可以对已有些IEnumerable接口扩充一个CopyToDataTable方法,使其可以将LINQ再次回到的var匿名类型转换成DataTable。来看下具体的兑现。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            // create sequence 
            Item[] items = new Item[] { new Book{Id = 1, Price = 13.50, Genre = “Comedy”, Author = “Jim Bob”}, 
                                        new Book{Id = 2, Price = 8.50, Genre = “Drama”, Author = “John Fox”},  
                                        new Movie{Id = 1, Price = 22.99, Genre = “Comedy”, Director = “Phil Funk”},
                                        new Movie{Id = 1, Price = 13.40, Genre = “Action”, Director = “Eddie Jones”}};

            var query1 = from i in items
                         where i.Price > 9.99
                         orderby i.Price
                         select i;

            // load into new DataTable
            DataTable table1 = query1.CopyToDataTable();

            this.dataGridView1.DataSource = table1;
        }
    }

    public class Item
    {
        public int Id { get; set; }
        public double Price { get; set; }
        public string Genre { get; set; }
    }

    public class Book : Item
    {
        public string Author { get; set; }
    }

    public class Movie : Item
    {
        public string Director { get; set; }
    }

    public static class DataSetLinqOperators
    {
        public static DataTable CopyToDataTable<T>(this IEnumerable<T> source)
        {
            return new ObjectShredder<T>().Shred(source, null, null);
        }

        public static DataTable CopyToDataTable<T>(this IEnumerable<T> source,
                                                    DataTable table, LoadOption? options)
        {
            return new ObjectShredder<T>().Shred(source, table, options);
        }

    }

    public class ObjectShredder<T>
    {
        private FieldInfo[] _fi;
        private PropertyInfo[] _pi;
        private Dictionary<string, int> _ordinalMap;
        private Type _type;

        public ObjectShredder()
        {
            _type = typeof(T);
            _fi = _type.GetFields();
            _pi = _type.GetProperties();
            _ordinalMap = new Dictionary<string, int>();
        }

        public DataTable Shred(IEnumerable<T> source, DataTable table, LoadOption? options)
        {
            if (typeof(T).IsPrimitive)
            {
                return ShredPrimitive(source, table, options);
            }

            if (table == null)
            {
                table = new DataTable(typeof(T).Name);
            }

            // now see if need to extend datatable base on the type T + build ordinal map
            table = ExtendTable(table, typeof(T));

            table.BeginLoadData();
            using (IEnumerator<T> e = source.GetEnumerator())
            {
                while (e.MoveNext())
                {
                    if (options != null)
                    {
                        table.LoadDataRow(ShredObject(table, e.Current), (LoadOption)options);
                    }
                    else
                    {
                        table.LoadDataRow(ShredObject(table, e.Current), true);
                    }
                }
            }
            table.EndLoadData();
            return table;
        }

        public DataTable ShredPrimitive(IEnumerable<T> source, DataTable table, LoadOption? options)
        {
            if (table == null)
            {
                table = new DataTable(typeof(T).Name);
            }

            if (!table.Columns.Contains(“Value”))
            {
                table.Columns.Add(“Value”, typeof(T));
            }

            table.BeginLoadData();
            using (IEnumerator<T> e = source.GetEnumerator())
            {
                Object[] values = new object[table.Columns.Count];
                while (e.MoveNext())
                {
                    values[table.Columns[“Value”].Ordinal] = e.Current;

                    if (options != null)
                    {
                        table.LoadDataRow(values, (LoadOption)options);
                    }
                    else
                    {
                        table.LoadDataRow(values, true);
                    }
                }
            }
            table.EndLoadData();
            return table;
        }

        public DataTable ExtendTable(DataTable table, Type type)
        {
            // value is type derived from T, may need to extend table.
            foreach (FieldInfo f in type.GetFields())
            {
                if (!_ordinalMap.ContainsKey(f.Name))
                {
                    DataColumn dc = table.Columns.Contains(f.Name) ? table.Columns[f.Name]
                        : table.Columns.Add(f.Name, f.FieldType);
                    _ordinalMap.Add(f.Name, dc.Ordinal);
                }
            }
            foreach (PropertyInfo p in type.GetProperties())
            {
                if (!_ordinalMap.ContainsKey(p.Name))
                {
                    DataColumn dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name]
                        : table.Columns.Add(p.Name, p.PropertyType);
                    _ordinalMap.Add(p.Name, dc.Ordinal);
                }
            }
            return table;
        }

        public object[] ShredObject(DataTable table, T instance)
        {

            FieldInfo[] fi = _fi;
            PropertyInfo[] pi = _pi;

            if (instance.GetType() != typeof(T))
            {
                ExtendTable(table, instance.GetType());
                fi = instance.GetType().GetFields();
                pi = instance.GetType().GetProperties();
            }

            Object[] values = new object[table.Columns.Count];
            foreach (FieldInfo f in fi)
            {
                values[_ordinalMap[f.Name]] = f.GetValue(instance);
            }

            foreach (PropertyInfo p in pi)
            {
                values[_ordinalMap[p.Name]] = p.GetValue(instance, null);
            }
            return values;
        }
    }
}

  
Item,Book,Movie都是自定义类型,扩大方法对IEnumerable泛型接口添加了能帮助任意档次并回到DataTable的点子CopyToDataTable,于是,大家可以直接对LINQ再次回到的var匿名类型应用CopyDoDataTable方法并将再次回到值赋值给DataTable对象。然后将DataTable直接绑定给DataGridView从而获取点击列标题举办数量排序的功效。还有稍稍复杂一点的利用,给一个代码片段的截图。

 

统计 1