1. 程式人生 > >【AutoMapper官方文件】DTO與Domin Model相互轉換(下)

【AutoMapper官方文件】DTO與Domin Model相互轉換(下)

寫在前面

  AutoMapper目錄:

  本篇目錄:

  關於AutoMapper寫到這基本的東西都差不多了,上一篇定義為靈活配置篇,本篇可以定義為擴充套件應用篇,加一些補充,關於AutoMapper的專案應用,網上找了幾篇英文文章,雖然看不懂,但是程式碼是相通的,感覺很不錯,主要是EntityFramework中運用AutoMapper,資料訪問中使用AutoMapper,有支援的,也有反對的,也有提出建議的,自己也正在摸索,希望有機會寫篇文章和大家分享下。

  插一句:寫這些東西,看的人真的很少,還不如像前幾天大家寫篇水文,來討論下C#的好壞增加點人氣,呵呵,但是如果是這種思想來程式設計真是不可饒恕,寫這種文章的目的不一定是分享給別人,也是對自己學習的另一種修煉,畢竟肚子沒有什麼東西,是寫不出來,也是在逼迫自己去學習,當去學習一點東西后,發現

其實並不像想象的那麼簡單,還有很多的東西要去學習,恨只恨自己晚生了幾年,還需努力。

Mapping Inheritance-對映繼承

  關於對映繼承,其實在“Lists and Array-集合和陣列”這一節點有提到,但是隻是說明下AutoMapper解決對映繼承所使用的方式,這邊我們說下關於AutoMapper在對映繼承中的一些特性,比如下面轉換示例:

1         public class Order { }
2         public class OnlineOrder : Order { }
3         public class MailOrder : Order { }
4 5 public class OrderDto { } 6 public class OnlineOrderDto : OrderDto { } 7 public class MailOrderDto : OrderDto { }

  源物件和目標物件存在繼承關係,和“Lists and Array”節點裡面的的示例一樣,我們首先要配置AutoMapper,新增型別對映關係和依賴關係,如下:

1             //配置 AutoMapper
2             Mapper.CreateMap<Order, OrderDto>()
3 .Include<OnlineOrder, OnlineOrderDto>() 4 .Include<MailOrder, MailOrderDto>(); 5 Mapper.CreateMap<OnlineOrder, OnlineOrderDto>(); 6 Mapper.CreateMap<MailOrder, MailOrderDto>();

  關於這三段程式碼的意義,在“Lists and Array”節點中也有說明,如果我們註釋掉第一段程式碼,我們在做派生類對映轉換的時候就會報錯,如果我們把下面兩段程式碼去掉,我們在做派生類對映轉換的時候就會對映到基類,說明第一段程式碼的意義是,不僅僅包含Order到OrderDto之間的型別對映,還包含Order與OrderDto所有派生類之間的對映,但是隻是宣告,如果要對派生類之間進行型別對映轉換,就還得需要建立派生類之間的型別對映關係。

  我們“Lists and Array”節點中這樣執行型別對映轉換:

1     var destinations = Mapper.Map<ParentSource[], ParentDestination[]>(sources);

  上面這段轉換程式碼是指定了源泛型型別(Source)和目標泛型型別型別(Dest),所以AutoMapper會根據指定的型別就可以進行轉換了,前提是型別對映關係配置正確,要不然就會報“AutoMapperConfigurationException”異常。如果我們不指定目標資料型別,然後就行轉換會怎樣呢?比如下面轉換:

1     var order = new OnlineOrder();
2     var mapped = Mapper.Map(order, order.GetType(), typeof(OrderDto));
3     Console.WriteLine("mapped Type:" + mapped.GetType());

  轉換效果:

  程式碼中我們並沒有指定目標資料型別,只是指定一個派生類的基類,如果按照我們的理解,這段程式碼執行的結果應該是:轉換結果mapped物件的型別應該是OrderDto型別,但是確是我們希望想要的OnlineOrderDto型別,雖然我們沒有指定目標型別為OnlineOrderDto,但是這一切AutoMapper都幫你做了,就是說AutoMapper會自動判斷目標型別與源資料型別存在的關係,並找出最合適的派生類型別。

Queryable Extensions (LINQ)-擴充套件查詢表示式

  注:關於Entity Framework中資料型別對映正在研究,網上找了很多英文文章,還在消化中,這一節點只是簡單的說下AutoMapper查詢表示式的用法,過幾天再整理一篇關於實體框架中運用資料型別對映的文章,功力不夠,還請包涵。

  當我們使用Entity Framework與AutoMapper結合進行查詢物件轉換的時候,使用Mapper.Map方法,就會發現查詢結果物件中的所有屬性和目標屬性物件屬性都會轉換,當然你也可以在查詢結果集中構建一個所需結果的示例,但是這樣做並不是可取的,AutoMapper的作者擴充套件了QueryableExtensions,使得我們在查詢的時候就可以實現轉換,比如下面示例:

 1         public class OrderLine
 2         {
 3             public int Id { get; set; }
 4             public int OrderId { get; set; }
 5             public Item Item { get; set; }
 6             public decimal Quantity { get; set; }
 7         }
 8         public class Item
 9         {
10             public int Id { get; set; }
11             public string Name { get; set; }
12         }
13 
14         public class OrderLineDTO
15         {
16             public int Id { get; set; }
17             public int OrderId { get; set; }
18             public string Item { get; set; }
19             public decimal Quantity { get; set; }
20         }
21 
22         public List<OrderLineDTO> GetLinesForOrder(int orderId)
23         {
24             Mapper.CreateMap<OrderLine, OrderLineDTO>()
25               .ForMember(dto => dto.Item, conf => conf.MapFrom(ol => ol.Item.Name));
26 
27             using (var context = new orderEntities())
28             {
29                 return context.OrderLines.Where(ol => ol.OrderId == orderId)
30                          .Project().To<OrderLineDTO>().ToList();
31             }
32         }

  程式碼中的.Project().To就是擴充套件的查詢表示式,詳細表達式程式碼:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Linq.Expressions;
  5 using System.Reflection;
  6 using System.Text.RegularExpressions;
  7 
  8 namespace DTO_AutoMapper使用詳解
  9 {
 10     public static class QueryableExtensions
 11     {
 12         public static ProjectionExpression<TSource> Project<TSource>(this IQueryable<TSource> source)
 13         {
 14             return new ProjectionExpression<TSource>(source);
 15         }
 16     }
 17 
 18     public class ProjectionExpression<TSource>
 19     {
 20         private static readonly Dictionary<string, Expression> ExpressionCache = new Dictionary<string, Expression>();
 21 
 22         private readonly IQueryable<TSource> _source;
 23 
 24         public ProjectionExpression(IQueryable<TSource> source)
 25         {
 26             _source = source;
 27         }
 28 
 29         public IQueryable<TDest> To<TDest>()
 30         {
 31              var queryExpression = GetCachedExpression<TDest>() ?? BuildExpression<TDest>();
 32 
 33             return _source.Select(queryExpression);
 34         }        
 35 
 36         private static Expression<Func<TSource, TDest>> GetCachedExpression<TDest>()
 37         {
 38             var key = GetCacheKey<TDest>();
 39 
 40             return ExpressionCache.ContainsKey(key) ? ExpressionCache[key] as Expression<Func<TSource, TDest>> : null;
 41         }
 42 
 43         private static Expression<Func<TSource, TDest>> BuildExpression<TDest>()
 44         {
 45             var sourceProperties = typeof(TSource).GetProperties();
 46             var destinationProperties = typeof(TDest).GetProperties().Where(dest => dest.CanWrite);
 47             var parameterExpression = Expression.Parameter(typeof(TSource), "src");
 48             
 49             var bindings = destinationProperties
 50                                 .Select(destinationProperty => BuildBinding(parameterExpression, destinationProperty, sourceProperties))
 51                                 .Where(binding => binding != null);
 52 
 53             var expression = Expression.Lambda<Func<TSource, TDest>>(Expression.MemberInit(Expression.New(typeof(TDest)), bindings), parameterExpression);
 54 
 55             var key = GetCacheKey<TDest>();
 56 
 57             ExpressionCache.Add(key, expression);
 58 
 59             return expression;
 60         }        
 61 
 62         private static MemberAssignment BuildBinding(Expression parameterExpression, MemberInfo destinationProperty, IEnumerable<PropertyInfo> sourceProperties)
 63         {
 64             var sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == destinationProperty.Name);
 65 
 66             if (sourceProperty != null)
 67             {
 68                 return Expression.Bind(destinationProperty, Expression.Property(parameterExpression, sourceProperty));
 69             }
 70 
 71             var propertyNames = SplitCamelCase(destinationProperty.Name);
 72 
 73             if (propertyNames.Length == 2)
 74             {
 75                 sourceProperty = sourceProperties.FirstOrDefault(src => src.Name == propertyNames[0]);
 76 
 77                 if (sourceProperty != null)
 78                 {
 79                     var sourceChildProperty = sourceProperty.PropertyType.GetProperties().FirstOrDefault(src => src.Name == propertyNames[1]);
 80 
 81                     if (sourceChildProperty != null)
 82                     {
 83                         return Expression.Bind(destinationProperty, Expression.Property(Expression.Property(parameterExpression, sourceProperty), sourceChildProperty));
 84                     }
 85                 }
 86             }
 87 
 88             return null;
 89         }
 90 
 91         private static string GetCacheKey<TDest>()
 92         {
 93             return string.Concat(typeof(TSource).FullName, typeof(TDest).FullName);
 94         }
 95 
 96         private static string[] SplitCamelCase(string input)
 97         {
 98             return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim().Split(' ');
 99         }
100     }    
101 }
View Code

  我們在前幾節點中說的自定義對映規則,其實也是屬於查詢表示式的一種,結合實體框架可以簡單的應用下,比如我們要對映到DTO中一個Count屬性,來計算查詢結果集中的數量,如下面程式碼:

1 Mapper.CreateMap<Customer, CustomerDto>()
2     .ForMember(d => d.FullName, opt => opt.MapFrom(c => c.FirstName + " " + c.LastName))
3     .ForMember(d => d.TotalContacts, opt => opt.MapFrom(c => c.Contacts.Count()));

  LINQ支援聚合查詢,AutoMapper支援LINQ的擴充套件方法。在自定義對映中,如果我們講屬性名稱TotalContacts改為ContactsCount,AutoMapper將自動匹配到COUNT()擴充套件方法和LINQ提供程式將轉化計數到相關子查詢彙總子記錄。AutoMapper還可以支援複雜的聚合和巢狀的限制,如果LINQ提供的表示式支援它,例如下面程式碼:

1 Mapper.CreateMap<Course, CourseModel>()
2     .ForMember(m => m.EnrollmentsStartingWithA,
3           opt => opt.MapFrom(c => c.Enrollments.Where(e => e.Student.LastName.StartsWith("A")).Count()));

  上面計算的是每門課程,學生名字開頭為“A”的學生數量。

  不是所有的對映選項都支援表示式,因為它必須有LINQ的支援,支援的有:

  • MapFrom
  • Ignore

  不支援的有:

  • Condition
  • DoNotUseDestinationValue
  • SetMappingOrder
  • UseDestinationValue
  • UseValue
  • ResolveUsing
  • Any calculated property on your domain object

Configuration-配置

Profile-修飾

  AutoMapper提供了個性化設定Profile,使得我們轉換後的資料格式可以多變,當然還可以配置全域性格式等等,需要繼承自Profile,並重寫Configure方法,然後在AutoMapper初始化的時候,講自定義配置新增到對映配置中,如下面示例:

 1         public class Order
 2         {
 3             public decimal Amount { get; set; }
 4         }
 5         public class OrderListViewModel
 6         {
 7             public string Amount { get; set; }
 8         }
 9         public class OrderEditViewModel
10         {
11             public string Amount { get; set; }
12         }
13         public class MoneyFormatter : ValueFormatter<decimal>
14         {
15             protected override string FormatValueCore(decimal value)
16             {
17                 return value.ToString("c");
18             }
19         }
20         public class ViewModelProfile : Profile
21         {
22             protected override void Configure()
23             {
24                 CreateMap<Order, OrderListViewModel>();
25                 ForSourceType<decimal>().AddFormatter<MoneyFormatter>();
26             }
27         }

  先建立了一個MoneyFormatter字元格式化類,然後建立ViewModelProfile配置類,在Configure方法中,新增型別對映關係,ForSourceType指的是講元資料型別新增格式化,配置使用程式碼:

 1         public void Example()
 2         {
 3             var order = new Order { Amount = 50m };
 4             //配置 AutoMapper
 5             Mapper.Initialize(cfg =>
 6             {
 7                 cfg.AddProfile<ViewModelProfile>(); 
 8                 cfg.CreateMap<Order, OrderEditViewModel>();
 9             });
10             //執行 mapping
11             var listViewModel = Mapper.Map<Order, OrderListViewModel>(order);
12             var editViewModel = Mapper.Map<Order, OrderEditViewModel>(order);
13 
14             Console.WriteLine("listViewModel.Amount:" + listViewModel.Amount);
15             Console.WriteLine("editViewModel.Amount:" + editViewModel.Amount);
16         }

  可以看到在Mapper.Initialize初始化的時候,把ViewModelProfile新增到AutoMapper配置中,泛型型別引數必須是Profile的派生類,因為我們在ViewModelProfile的Configure方法中添加了Order到OrderListViewModel型別對映關係,所以我們再初始化的時候就不需要添加了,轉換效果:

Naming Conventions-命名約定

  在“Flattening-複雜到簡單”節點中,我們說到AutoMapper對映轉換遵循PascalCase(帕斯卡命名規則),所以我們在型別名稱命名要按照PascalCase進行命名,除了預設的命名規則,AutoMapper還提供了一種命名規則,如下:

1 Mapper.Initialize(cfg => {
2   cfg.SourceMemberNamingConvention = new LowerUnderscoreNamingConvention();
3   cfg.DestinationMemberNamingConvention = new PascalCaseNamingConvention();
4 });

  SourceMemberNamingConvention表示源資料型別命名規則,DestinationMemberNamingConvention表示目標資料型別命名規則,LowerUnderscoreNamingConvention和PascalCaseNamingConvention是AutoMapper提供的兩個命名規則,前者命名是小寫幷包含下劃線,後者就是帕斯卡命名規則,所以對映轉換的效果是:property_name -> PropertyName。

  當然除了在AutoMapper初始化的時候配置命名規則,也可以在Profile中新增全域性配置,如下:

1 public class OrganizationProfile : Profile 
2 {
3   protected override void Configure() 
4   {
5     SourceMemberNamingConvention = new LowerUnderscoreNamingConvention();
6     DestinationMemberNamingConvention = new PascalCaseNamingConvention();
7   }
8 }

Conditional Mapping-條件對映

  AutoMapper允許在型別對映之前新增條件,例如下面示例:

 1         public class Foo
 2         {
 3             public int baz { get; set; }
 4         }
 5         public class Bar
 6         {
 7             public uint baz { get; set; }
 8         }
 9         public void Example()
10         {
11             var foo = new Foo { baz = 1 };
12             //配置 AutoMapper
13             Mapper.CreateMap<Foo, Bar>()
14                     .ForMember(dest => dest.baz, opt => opt.Condition(src => (src.baz >= 0)));
15             //執行 mapping
16             var result = Mapper.Map<Foo, Bar>(foo);
17 
18             Console.WriteLine("result.baz:" + result.baz);
19         }

  上面示例表示當源資料baz大於0的時候,才能執行對映,關鍵字是Condition,Condition方法接受一個Func<TSource, bool>型別引數,注意已經指定返回值為bool型別,方法簽名:

1         //
2         // 摘要:
3         //     Conditionally map this member
4         //
5         // 引數:
6         //   condition:
7         //     Condition to evaluate using the source object
8         void Condition(Func<TSource, bool> condition);

  轉換效果:

AutoMapper版本變化點

  在AutoMapper1.1版本中,如果我們要對型別巢狀對映中加入自定義型別對映,比如下面示例:

1     Mapper.CreateMap<Order, OrderDto>()
2           .Include<OnlineOrder, OnlineOrderDto>()
3           .Include<MailOrder, MailOrderDto>()
4           .ForMember(o=>o.Id, m=>m.MapFrom(s=>s.OrderId));
5     Mapper.CreateMap<OnlineOrder, OnlineOrderDto>()
6           .ForMember(o=>o.Id, m=>m.MapFrom(s=>s.OrderId));
7     Mapper.CreateMap<MailOrder, MailOrderDto>()
8           .ForMember(o=>o.Id, m=>m.MapFrom(s=>s.OrderId));

  可以看出,我們需要在每個型別對映的地方要加:.ForMember(o=>o.Id, m=>m.MapFrom(s=>s.OrderId));但是Order、OnlineOrder和MailOrder存在繼承關係,難道我們如果再加一個派生類對映,就得加一段這樣程式碼,這樣就會程式碼就會變得難以維護。在AutoMapper2.0版本中解決了這一問題,只需要下面這樣配置就可以了:

1     Mapper.CreateMap<Order, OrderDto>()
2           .Include<OnlineOrder, OnlineOrderDto>()
3           .Include<MailOrder, MailOrderDto>()
4           .ForMember(o=>o.Id, m=>m.MapFrom(s=>s.OrderId));
5     Mapper.CreateMap<OnlineOrder, OnlineOrderDto>();
6     Mapper.CreateMap<MailOrder, MailOrderDto>();

型別對映優先順序

  1. Explicit Mapping (using .MapFrom())-顯式對映:優先順序最高,我們使用MapFrom方法定義對映規則,比如:.ForMember(dest => dest.EventDate, opt => opt.MapFrom(src => src.EventDate.Date))
  2. Inherited Explicit Mapping-繼承的顯式對映:就是存在繼承關係的MapFrom定義對映規則對映。
  3. Ignore Property Mapping-忽略屬性對映:使用Ignore方法指定屬性忽略對映,比如:Mapper.CreateMap<Source, Destination>().ForMember(dest => dest.SomeValuefff, opt => opt.Ignore());
  4. Convention Mapping (Properties that are matched via convention)-公約對映:公約對映即符合PascalCase命名規則的對映。如Source類中有Value屬性,Dest類中也有Value屬性,Source和Dest對映關係即是公約對映。
  5. Inherited Ignore Property Mapping-繼承的忽略屬性對映:優先順序最低,就是存在繼承關係的忽略屬性對映。

  我們舉個簡單示例來說明下對映優先順序:

 1         //Domain Objects
 2         public class Order { }
 3         public class OnlineOrder : Order
 4         {
 5             public string Referrer { get; set; }
 6         }
 7         public class MailOrder : Order { }
 8 
 9         //Dtos
10         public class OrderDto
11         {
12             public string Referrer { get; set; }
13         }
14         public void Example2()
15         {
16             //配置 AutoMapper
17             Mapper.CreateMap<Order, OrderDto>()
18                   .Include<OnlineOrder, OrderDto>()
19                   .Include<MailOrder, OrderDto>()
20                   .ForMember(o => o.Referrer, m => m.Ignore());
21             Mapper.CreateMap<OnlineOrder, OrderDto>();
22             Mapper.CreateMap<MailOrder, OrderDto>();
23 
24             //執行 Mapping
25             var order = new OnlineOrder { Referrer = "google" };
26             var mapped = Mapper.Map(order, order.GetType(), typeof(OrderDto));
27         }

  轉換後mapped物件的Referrer屬性值為“google”,但是你發現我們在配置對映規則的時候,不是把Referrer屬性給Ignore(忽略)了嗎?因為OnlineOrder的ReferrerOrderDto的Referrer屬性符合PascalCase命名規則,即是公約對映,雖然忽略屬性對映的優先順序比公約對映高,但是上面示例中Order和OnlineOrder存在繼承關係,即是繼承的忽略屬性對映,所以優先順序比公約對映要低。

後記

  如果你覺得本篇文章對你有所幫助,請點選右下部“推薦”,^_^

  參考資料:

相關推薦

AutoMapper官方DTODomin Model相互轉換

寫在前面   AutoMapper目錄:   本篇目錄:   關於AutoMapper寫到這基本的東西都差不多了,上一篇定義為靈活配置篇,本篇可以定義為擴充套件應用篇,加一些補充,關於AutoMapper的專案應用,網上找了幾篇英文文章,雖然看不懂,但是程式碼是相通的,感覺很不錯,主要是Enti

AutoMapper官方DTODomin Model相互轉換

寫在前面   AutoMapper目錄:   本篇目錄:   上一篇《【道德經】漫談實體、物件、DTO及AutoMapper的使用 》,因為內容寫的有點跑偏,關於AutoMapper的使用最後只是簡單寫了下,很明顯這種簡單的使用方式不能滿足專案中複雜的需要,網上找了下AutoMapper相關文件

AutoMapper官方DTODomin Model相互轉換

寫在前面   AutoMapper目錄:   本篇目錄:   隨著AutoMapper的學習深入,發現AutoMapper在物件轉換方面(Object-Object Mapping)還蠻強大的,當時使用AutoMapper的場景是DTO與Domin Model相互轉換,所以文章的標題就是這個(標

android官方android AIDL

概述      AIDL(安卓介面解釋語言)和其他的IDLs類似。可以定義程式介面讓客戶端和service進行跨程序的通訊(IPC)。在android中,一個程序通常不能訪問另一個程序的記憶體。所以,他們的物件需要被分解成更原始的單位,直到系統可以理解,並且集結這些物件穿

Android官方翻譯Android官方-Activities(一)

Activity是可以給使用者提供互動操作的程式元件,例如打電話,拍照,傳送郵件,抑或者是顯示地圖。通常視窗會填滿螢幕,但是也可以做到比螢幕小或者是懸浮在視窗頂部。 App通常由多個Activities組成,它們之間支援相互跳轉。一般情況下,每個Activit

pytest官方解讀fixtures - 1.什麼是fixtures

在深入瞭解fixture之前,讓我們先看看什麼是`測試`。 ### 一、測試的構成 其實說白了,測試就是在特定的環境、特定的場景下、執行特定的行為,然後確認結果與期望的是否一致。 就拿最常見的登入來說,完成一次正常的登入場景,需要可用的測試環境,可以正常登入的賬號和密碼。 然後,用這個賬號密碼進行登入操

pytest官方解讀fixtures - 2. fixtures的呼叫方式

既然fixtures是給執行測試做準備工作的,那麼pytest如何知道哪些測試函式 或者 fixtures要用到哪一個fixtures呢? 說白了,就是fixtures的呼叫。 ### 一、測試函式宣告傳參請求fixture 測試函式通過將fixture宣告為引數來請求fixture。 ``` def te

pytest官方解讀fixtures - 8. yield和addfinalizer的區別填坑

在[上一章](https://www.cnblogs.com/pingguo-softwaretesting/p/14479170.html)中,文末留下了一個坑待填補,疑問是這樣的: 目前從官方文件中看到的是 ``` We have to be careful though, because pytest

Pulsar官方翻譯-入門必看-概念和架構-概覽Pulsar Overview

官網原文標題《Concepts and Architecture--Pulsar Overview》 翻譯時間:2018-09-28 譯者:本文介紹了Pulsar的起源和現狀,以及主要特性。 後續閱讀:《Messaging Concepts》 譯者序言: 由

小白學PyTorch21 Keras的API詳解池化、Normalization層

文章來自微信公眾號:【機器學習煉丹術】。作者WX:cyx645016617. 參考目錄: [toc] 下篇的內容中,主要講解這些內容: - 四個的池化層; - 兩個Normalization層; ## 1 池化層 和卷積層相對應,每一種池化層都有```1D,2D,3D```三種類型,這裡主要介紹2D處理影象

unicodeGB2312的相互轉換js

上回說到,我們用C語言輸出了一張GB2312的全部字元表……同時也說,有了這個,我們就能實現使用js進行unicode和GB2312之間的轉碼了……再加上前回(其實是幾年之前)說到,用js沒有內建函式實現這兩者的轉碼,如果用到,一般都是藉助於vbs……這使得我的BF直譯器(

xmlbean間相互轉換補充

今天x被stream對xmlnode的屬性(attribute)解析的問題一直困擾著,查詢了很久都告知我要手寫一個Converter,那豈不意味著我每解析一個xml檔案,就得寫一次Converter,那樣太腦殘了,最後搜尋到其實可以用註解解決這個問題 XStream常用註解

AutoMapper官方(二)升級指南

初始化 您現在必須使用Mapper.Initialize或new MapperConfiguration()來初始化AutoMapper。如果您希望保持靜態使用,請使用Mapper.Initialize。 如果你有很多的Mapper.CreateMap呼叫,把它們移動到一個Profile,或者Mapper

pythonnumpy庫陣列拼接np.concatenate官方詳解例項

在實踐過程中,會經常遇到陣列拼接的問題,基於numpy庫concatenate是一個非常好用的陣列操作函式。 1、concatenate((a1, a2, …), axis=0)官方文件詳解 concatenate(...) concatenate(

pySerial3.4官方6、示例

示例 Miniterm  Miniterm現在可用作模組而不是示例。有關詳細資訊,請參閱serial.tools.miniterm。 miniterm.py miniterm計劃。 setup-miniterm-py2exe.py 這是Windows的py2exe安

pySerial3.4官方4、工具

工具 serial.tools.list_ports  可以執行此模組以獲取埠列表()。它還包含以下功能。python -m serial.tools.list_ports serial.tools.list_ports.comports(include_l

pySerial3.4官方3、pySerial API

pySerial API  類 本地埠 類serial.Serial __init__(port = None,baudrate = 9600,bytesize = EIGHTBITS,parity = PARITY_NONE,stopbits = STOPBITS_ONE

pySerial3.4官方2、簡介

簡介 開啟串列埠 開啟“9600,8,N,1”的埠,沒有超時: >>> import serial >>> ser = serial.Serial('/dev/ttyUSB0') # open serial port >>> pri

Gradle官方翻譯起步2:建立構建掃描

構建掃描是對構建的可分享的專門記錄,可以看到“構建中發生了那些行為以及為什麼會發生這種行為”。通過在專案中使用構建掃描外掛,開發者可以免費地在https://scans.gradle.com/上釋出構建掃描。 將要建立的 本文會展示如何在不對任何構建指令碼進行

cocos2d-js官方十七、事件分發機制

簡介 遊戲開發中一個很重要的功能就是互動,如果沒有與使用者的互動,那麼遊戲將變成動畫,而處理使用者互動就需要使用事件監聽器了。 總概: 事件監聽器(cc.EventListener) 封裝使用者的事件處理邏輯事件管理器(cc.eventManager) 管理使用者註