解读WPF中的Xaml

1.Overview

这篇文章主要分享从源代码角度解读wpf中xaml。由于源码查看起来错综复杂“随便找一个对象按下F12就是一个新的世界”,看源码的感觉就是在盗梦空间里来回穿梭;所以也是耗费很长的时间去阅读源码然后根据自己的理解编写文章和贴出部分关键源码。

2.Detail

大概将从编译、读取、加载这几个维度来解读。以防后面看源码会晕,先直接讲结果;

  • 编写(可通过vs完成)

be384c195876ffe76691c9e6fbda9eeb.png

  • 编译(可通过vs完成)

fdb9960a385e472016184eb7232bf0d7.png

  • 读取、加载

d3169573049b6e28a47e4c08de68cdbb.png

有的帅气的观众就会问了,这些研究在实际在项目中应用场景是什么?

         选择性的加载xaml(baml)文件来达到更改UI的操作。

  • 动态换肤,大家都用过手机app每到过年过节都会看到界面上会出现对应的主题,那么我们就可以在程序内设定到了某个节日直接加载对应主题界面的xaml(baml)文件来达到这种效果,对于动态皮肤场景来说,在运行时加载和解析XAML是有意义的。

  • 加载不同的.xaml(.baml)文件,以适应不同分辨率的布局

  • 简单固定的UI美工人员将设计稿转换为位图,可使用blend或者 expression design转成对应的wpf界面

还可以适配不同的业务要求。可能这种延伸就是研究的意义吧

(1)编译xaml

XAML不仅要能够解决涉及协作问题,它还需要快速运行。尽管基于XML格式可以很灵活并且很容易地迁移到其他平台和工具,但未必是有效的选择。XML的涉及目标是具有逻辑性、易读而且简单,没有被压缩。WPF 使用 BAML(Binaiy Application Markup Language,二进制应用程序标记语言)来克服这 个缺点。BAML 并非新事物,它实际上就是 XAML 的二进制表示,当在 Visual Studio 中编译 WPF 应用程序时,所有 XAML 文件都被转换为 BAML这些 BAML 然后作为资源被嵌入到最 终的 DLL 或 EXE 程序集中。BAML 是标记化的,这意味着较长的 XAML 被较短的标记替代。BAML 不仅明显小一些,还对其进行了优化,从而使它在运行时能够更快地解析。并成为一个内嵌资源;

BAML由VS编译生成存在,obj目录的debug下;

078901417888af64b594cca51fc62f1a.png

通过IL反编译项目文件之后,可以看到编译完成之后将会被连接到工程的“资源清单”当中。

4378489172def12e40479a54fedf3623.png

使用Assembly的GetManifestResourceStream方法,可以在运行期获取到这个二进制流

Assembly asm = Assembly.GetExecutingAssembly( );
Stream s = asm.GetManifestResourceStream("StreamName");

(2)读取、加载xaml(baml)

使用代码和未经编译的标记(XAML),这种具体方式对于某些特殊情况是很苻意义的* 例如创建高度动态化的用户界面。这种方式在运行时使用 System.Windows.Markup 名 称空间中的 从 XAML 文件中加载部分用户界面。使用代码和编译过的标记(BAML),对于 WPF 而言这是一种更好的方式,也是 Visual Studio 支持的一种方式。这种方式为每个窗口创建一个 XAML 橫板,这个 XAML 模板 被编译为 BAML,并嵌入到最终的程序集中。编译过的 BAML 在运行时被提取出来, 用于重新生成用户界面。

  • 1.当客户端程序被启动时Runtime接管代码来创建window实例

internal object CreateInstanceImpl(BindingFlags bindingAttr,Binder binder,object[] args,CultureInfo culture,object[] activationAttributes,ref StackCrawlMark stackMark){this.CreateInstanceCheckThis();object obj = (object) null;try{try{if (activationAttributes != null)ActivationServices.PushActivationAttributes((Type) this, activationAttributes);if (args == null)args = EmptyArray<object>.Value;int length = args.Length;if (binder == null)binder = Type.DefaultBinder;if (length == 0 && (bindingAttr & BindingFlags.Public) != BindingFlags.Default && (bindingAttr & BindingFlags.Instance) != BindingFlags.Default && (this.IsGenericCOMObjectImpl() || this.IsValueType)){obj = this.CreateInstanceDefaultCtor((bindingAttr & BindingFlags.NonPublic) == BindingFlags.Default, false, true, ref stackMark);}else{ConstructorInfo[] constructors = this.GetConstructors(bindingAttr);List<MethodBase> methodBaseList = new List<MethodBase>(constructors.Length);Type[] argumentTypes = new Type[length];for (int index = 0; index < length; ++index){if (args[index] != null)argumentTypes[index] = args[index].GetType();}for (int index = 0; index < constructors.Length; ++index){if (RuntimeType.FilterApplyConstructorInfo((RuntimeConstructorInfo) constructors[index], bindingAttr, CallingConventions.Any, argumentTypes))methodBaseList.Add((MethodBase) constructors[index]);}MethodBase[] methodBaseArray = new MethodBase[methodBaseList.Count];methodBaseList.CopyTo(methodBaseArray);if (methodBaseArray != null && methodBaseArray.Length == 0)methodBaseArray = (MethodBase[]) null;if (methodBaseArray == null){if (activationAttributes != null){ActivationServices.PopActivationAttributes((Type) this);activationAttributes = (object[]) null;}throw new MissingMethodException(Environment.GetResourceString("MissingConstructor_Name", (object) this.FullName));}object state = (object) null;MethodBase methodBase;try{methodBase = binder.BindToMethod(bindingAttr, methodBaseArray, ref args, (ParameterModifier[]) null, culture, (string[]) null, out state);}catch (MissingMethodException ex){methodBase = (MethodBase) null;}if (methodBase == (MethodBase) null){if (activationAttributes != null){ActivationServices.PopActivationAttributes((Type) this);activationAttributes = (object[]) null;}throw new MissingMethodException(Environment.GetResourceString("MissingConstructor_Name", (object) this.FullName));}if (RuntimeType.DelegateType.IsAssignableFrom(methodBase.DeclaringType))new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();if (methodBase.GetParametersNoCopy().Length == 0){if (args.Length != 0)throw new NotSupportedException(string.Format((IFormatProvider) CultureInfo.CurrentCulture, Environment.GetResourceString("NotSupported_CallToVarArg")));obj = Activator.CreateInstance((Type) this, true);}else{obj = ((ConstructorInfo) methodBase).Invoke(bindingAttr, binder, args, culture);if (state != null)binder.ReorderArgumentArray(ref args, state);}}}finally{if (activationAttributes != null){ActivationServices.PopActivationAttributes((Type) this);activationAttributes = (object[]) null;}}}catch (Exception ex){throw;}return obj;}
  • 2.Window构造函数调用Application.LoadComponent读取创建.xaml(baml)

3220a15fc00ddedd9918cd0c99c4e01a.png

IL反编译后的代码

/// <summary>
/// MainWindow
/// </summary>
public partial class MainWindow : System.Windows.Window, System.Windows.Markup.IComponentConnector {#line 10 "..\..\..\MainWindow.xaml"[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")]internal System.Windows.Controls.TextBox textBox;#line default#line hiddenprivate bool _contentLoaded;/// <summary>/// InitializeComponent/// </summary>[System.Diagnostics.DebuggerNonUserCodeAttribute()][System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "6.0.0.0")]public void InitializeComponent() {if (_contentLoaded) {return;}_contentLoaded = true;System.Uri resourceLocater = new System.Uri("/WpfApp1;component/mainwindow.xaml", System.UriKind.Relative);#line 1 "..\..\..\MainWindow.xaml"System.Windows.Application.LoadComponent(this, resourceLocater);#line default#line hidden}[System.Diagnostics.DebuggerNonUserCodeAttribute()][System.CodeDom.Compiler.GeneratedCodeAttribute("PresentationBuildTasks", "6.0.0.0")][System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)][System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")][System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")][System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")]void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) {switch (connectionId){case 1:this.textBox = ((System.Windows.Controls.TextBox)(target));return;}this._contentLoaded = true;}
}
  • 3.Application.LoadComponent()加载baml

public static void LoadComponent(object component, Uri resourceLocator)
{if (component == null)throw new ArgumentNullException(nameof (component));if (resourceLocator == (Uri) null)throw new ArgumentNullException(nameof (resourceLocator));if (resourceLocator.OriginalString == null)throw new ArgumentException(SR.Get("ArgumentPropertyMustNotBeNull", (object) nameof (resourceLocator), (object) "OriginalString"));Uri curComponentUri = !resourceLocator.IsAbsoluteUri ? new Uri(BaseUriHelper.PackAppBaseUri, resourceLocator) : throw new ArgumentException(SR.Get("AbsoluteUriNotAllowed"));ParserContext parserContext = new ParserContext();parserContext.BaseUri = curComponentUri;Stream stream;bool closeStream;if (Application.IsComponentBeingLoadedFromOuterLoadBaml(curComponentUri)){NestedBamlLoadInfo nestedBamlLoadInfo = Application.s_NestedBamlLoadInfo.Peek();stream = nestedBamlLoadInfo.BamlStream;stream.Seek(0L, SeekOrigin.Begin);parserContext.SkipJournaledProperties = nestedBamlLoadInfo.SkipJournaledProperties;nestedBamlLoadInfo.BamlUri = (Uri) null;closeStream = false;}else{PackagePart resourceOrContentPart = Application.GetResourceOrContentPart(resourceLocator);ContentType contentType = new ContentType(resourceOrContentPart.ContentType);stream = resourceOrContentPart.GetStream();closeStream = true;if (!MimeTypeMapper.BamlMime.AreTypeAndSubTypeEqual(contentType))throw new Exception(SR.Get("ContentTypeNotSupported", (object) contentType));}if (!(stream is IStreamInfo streamInfo) || streamInfo.Assembly != component.GetType().Assembly)throw new Exception(SR.Get("UriNotMatchWithRootType", (object) component.GetType(), (object) resourceLocator));XamlReader.LoadBaml(stream, parserContext, component, closeStream);
}

      XamlReader.LoadBaml细节代码

internal static object LoadBaml(Stream stream,ParserContext parserContext,object parent,bool closeStream)
{object p1 = (object) null;EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Event.WClientParseBamlBegin, (object) parserContext.BaseUri);if (TraceMarkup.IsEnabled)TraceMarkup.Trace(TraceEventType.Start, TraceMarkup.Load);try{if (stream is IStreamInfo streamInfo2)parserContext.StreamCreatedAssembly = streamInfo2.Assembly;Baml2006ReaderSettings bamlReaderSettings = XamlReader.CreateBamlReaderSettings();bamlReaderSettings.BaseUri = parserContext.BaseUri;bamlReaderSettings.LocalAssembly = streamInfo2.Assembly;if (bamlReaderSettings.BaseUri == (Uri) null || string.IsNullOrEmpty(bamlReaderSettings.BaseUri.ToString()))bamlReaderSettings.BaseUri = BaseUriHelper.PackAppBaseUri;Baml2006ReaderInternal baml2006ReaderInternal = new Baml2006ReaderInternal(stream, new Baml2006SchemaContext(bamlReaderSettings.LocalAssembly), bamlReaderSettings, parent);Type type = (Type) null;if (streamInfo2.Assembly != (Assembly) null){try{type = XamlTypeMapper.GetInternalTypeHelperTypeFromAssembly(parserContext);}catch (Exception ex){if (CriticalExceptions.IsCriticalException(ex))throw;}}if (type != (Type) null){XamlAccessLevel xamlAccessLevel = XamlAccessLevel.AssemblyAccessTo(streamInfo2.Assembly);new XamlLoadPermission(xamlAccessLevel).Assert();try{p1 = WpfXamlLoader.LoadBaml((System.Xaml.XamlReader) baml2006ReaderInternal, parserContext.SkipJournaledProperties, parent, xamlAccessLevel, parserContext.BaseUri);}finally{CodeAccessPermission.RevertAssert();}}elsep1 = WpfXamlLoader.LoadBaml((System.Xaml.XamlReader) baml2006ReaderInternal, parserContext.SkipJournaledProperties, parent, (XamlAccessLevel) null, parserContext.BaseUri);if (p1 is DependencyObject dependencyObject2)dependencyObject2.SetValue(BaseUriHelper.BaseUriProperty, (object) bamlReaderSettings.BaseUri);if (p1 is Application application2)application2.ApplicationMarkupBaseUri = XamlReader.GetBaseUri(bamlReaderSettings.BaseUri);}finally{if (TraceMarkup.IsEnabled)TraceMarkup.Trace(TraceEventType.Stop, TraceMarkup.Load, p1);EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Event.WClientParseBamlEnd, (object) parserContext.BaseUri);if (closeStream && stream != null)stream.Close();}return p1;
}
  • 4.加载控件对象

提取BAML(编译过的XAML)解析并创建每个定义的控件对象,设置属性、关联事件等内容。

internal static object LoadBamlStreamWithSyncInfo(Stream stream, ParserContext pc)
{if (Application.s_NestedBamlLoadInfo == null)Application.s_NestedBamlLoadInfo = new Stack<NestedBamlLoadInfo>();NestedBamlLoadInfo nestedBamlLoadInfo = new NestedBamlLoadInfo(pc.BaseUri, stream, pc.SkipJournaledProperties);Application.s_NestedBamlLoadInfo.Push(nestedBamlLoadInfo);try{return XamlReader.LoadBaml(stream, pc, (object) null, true);}finally{Application.s_NestedBamlLoadInfo.Pop();if (Application.s_NestedBamlLoadInfo.Count == 0)Application.s_NestedBamlLoadInfo = (Stack<NestedBamlLoadInfo>) null;}
}

循环遍历所有xaml里的标签节点生成窗体内的内容。

private static object Load(System.Xaml.XamlReader xamlReader,IXamlObjectWriterFactory writerFactory,bool skipJournaledProperties,object rootObject,XamlObjectWriterSettings settings,Uri baseUri)
{XamlContextStack<WpfXamlFrame> stack = new XamlContextStack<WpfXamlFrame>((Func<WpfXamlFrame>) (() => new WpfXamlFrame()));int persistId = 1;settings.AfterBeginInitHandler = (EventHandler<XamlObjectEventArgs>) ((sender, args) =>{if (EventTrace.IsEnabled(EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose)){IXamlLineInfo xamlLineInfo = xamlReader as IXamlLineInfo;int num1 = -1;int num2 = -1;if (xamlLineInfo != null && xamlLineInfo.HasLineInfo){num1 = xamlLineInfo.LineNumber;num2 = xamlLineInfo.LinePosition;}int num3 = (int) EventTrace.EventProvider.TraceEvent(EventTrace.Event.WClientParseXamlBamlInfo, EventTrace.Keyword.KeywordPerf | EventTrace.Keyword.KeywordXamlBaml, EventTrace.Level.Verbose, (object) (args.Instance == null ? 0L : PerfService.GetPerfElementID(args.Instance)), (object) num1, (object) num2);}if (args.Instance is UIElement instance3){int num = persistId++;instance3.SetPersistId(num);}XamlSourceInfoHelper.SetXamlSourceInfo(args.Instance, args, baseUri);if (args.Instance is DependencyObject instance4 && stack.CurrentFrame.XmlnsDictionary != null){XmlnsDictionary xmlnsDictionary = stack.CurrentFrame.XmlnsDictionary;xmlnsDictionary.Seal();XmlAttributeProperties.SetXmlnsDictionary(instance4, xmlnsDictionary);}stack.CurrentFrame.Instance = args.Instance;});XamlObjectWriter xamlWriter = writerFactory == null ? new XamlObjectWriter(xamlReader.SchemaContext, settings) : writerFactory.GetXamlObjectWriter(settings);IXamlLineInfo xamlLineInfo1 = (IXamlLineInfo) null;try{xamlLineInfo1 = xamlReader as IXamlLineInfo;IXamlLineInfoConsumer xamlLineInfoConsumer = (IXamlLineInfoConsumer) xamlWriter;bool shouldPassLineNumberInfo = false;if (xamlLineInfo1 != null && xamlLineInfo1.HasLineInfo && xamlLineInfoConsumer != null && xamlLineInfoConsumer.ShouldProvideLineInfo)shouldPassLineNumberInfo = true;IStyleConnector styleConnector = rootObject as IStyleConnector;WpfXamlLoader.TransformNodes(xamlReader, xamlWriter, false, skipJournaledProperties, shouldPassLineNumberInfo, xamlLineInfo1, xamlLineInfoConsumer, stack, styleConnector);xamlWriter.Close();return xamlWriter.Result;}catch (Exception ex){if (CriticalExceptions.IsCriticalException(ex) || !XamlReader.ShouldReWrapException(ex, baseUri)){throw;}else{XamlReader.RewrapException(ex, xamlLineInfo1, baseUri);return (object) null;}}
}
// Get the XAML content from an external file.
DependencyObject rootElement;
using (FileStream fs = new FileStrearn(xamlFile, FileMode Open)){
rootElement = (DependencyObject)XamlReader.Load(fs);
}// Insert the markup into this window.
this.Content = rootElement;
// Find the control with the appropriate
buttonl = (Button)LogicalTreeHelper.FindLogicalNode(rootElement, ibuttonl");
name.
// Wire up the event handler.
buttonl.Click += buttonl 'Click

【截选内容1,这一段引用lindexi文章内的内容,原文地址在文章末尾】在 WPF 中,在 XAML 里面定义的对象的创建,实际上不是完全通过反射来进行创建的,在WPF框架里面,有进行了一系列的优化。将会通过 XamlTypeInvoker 的 CreateInstance 方法来进行对象的创建,而默认的 XamlTypeInvoker 的 CreateInstance 定义如下。还有其他精彩内容在原文里可以查看;

public virtual object CreateInstance(object[] arguments){ThrowIfUnknown();if (!_xamlType.UnderlyingType.IsValueType && (arguments == null || arguments.Length == 0)){object result = DefaultCtorXamlActivator.CreateInstance(this);if (result != null){return result;}}return CreateInstanceWithActivator(_xamlType.UnderlyingType, arguments);}private object CreateInstanceWithActivator(Type type, object[] arguments){return SafeReflectionInvoker.CreateInstance(type, arguments);}

【截选内容2,这一段引用lindexi文章内的内容,原文地址在文章末尾】

在 EnsureConstructorDelegate 方法里面将会判断如果对象是公开的,那么尝试获取默认构造函数,将默认构造函数做成委托。此时的性能将会是类型第一次进入的时候的速度比较慢,但是后续进入的时候就能使用委托创建,此时性能将会比较好。通过反射创建委托提升性能的方法,详细请看 .NET Core/Framework 创建委托以大幅度提高反射调用的性能 - walterlv

private static bool EnsureConstructorDelegate(XamlTypeInvoker type)
{// 如果类型初始化过构造函数创建,那么返回,这是缓存的方法if (type._constructorDelegate != null){return true;}// 如果不是公开的方法,那么将无法使用反射创建委托的科技if (!type.IsPublic){return false;}// 反射获取对象的构造函数Type underlyingType = type._xamlType.UnderlyingType.UnderlyingSystemType;// Look up public ctors only, for equivalence with Activator.CreateInstanceConstructorInfo tConstInfo = underlyingType.GetConstructor(Type.EmptyTypes);IntPtr constPtr = tConstInfo.MethodHandle.GetFunctionPointer();// 反射创建委托,这样下次访问就不需要使用反射,可以提升性能// This requires Reflection PermissionAction<object> ctorDelegate = ctorDelegate =(Action<object>)s_actionCtor.Invoke(new object[] { null, constPtr });type._constructorDelegate = ctorDelegate;return true;
}

也就是说只有第一次的类型进入才会调用反射创建委托用来提升性能,之后的进入将会使用第一次创建出来的委托来创建对象,这样能提升性能。

4.Reference

dotnet/wpf: WPF is a .NET Core UI framework for building Windows desktop applications. (github.com)

dotnet 读 WPF 源代码笔记 XAML 创建对象的方法 (lindexi.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293621.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

寒门博士分享读博经历成“抖音网红”惹争议,博士该这么“不正经”吗?

全世界只有3.14 % 的人关注了爆炸吧知识最近在抖音上&#xff0c;一个名叫“相宜”的主播火了。短短几个月时间内&#xff0c;她就涨粉940万。而和一般网红不同的是&#xff0c;相宜是一位刚毕业的博士。带火她的视频&#xff0c;是她自述博士毕业后的感想&#xff0c;目前已经…

Android Nine-patch

做了好多客户端软件了&#xff0c;突然发现里面有好多图片都是重复的&#xff0c;个别只是大小不一样&#xff0c;每次都使用大量图片&#xff0c;导致软件过大&#xff0c;项目总结的时候才发现Android已经提供了一种解决方案了&#xff0c;这就是NinePatchDrawable&#xff0…

稍微成型点的用WEBSOCKET实现的实时日志LOG输出

难的是还是就地用JS显示出来相关的发布进度。 还好&#xff0c;花了一下午实现了。 可以移植到项目中去罗。。。 websocket.py&#xff1a; import tornado.ioloop import tornado.web import tornado.websocket from tornado.ioloop import IOLoop from datetime import timed…

.NET6之MiniAPI(四):配置

配置文件&#xff0c;是一个每个应用服务程序常用的功能&#xff0c;从原来的终端应用时代&#xff0c;到现在的元宇宙时代&#xff0c;配置都是很悠然自得的存在。asp.net core提供了强大的配置文件访问机制&#xff0c;不管是MVC API还是MiniAPI&#xff0c;使用方式都是相同…

.NET 6新特性试用 | PeriodicTimer

前言在.NET中&#xff0c;已经存在了5个Timer类&#xff1a;System.Threading.TimerSystem.Timers.TimerSystem.Web.UI.TimerSystem.Windows.Forms.TimerSystem.Windows.Threading.DispatcherTimer不管以前这样设计的原因&#xff0c;现在.NET 6又为我们增加了一个新Timer&…

ChatForFun 公众号使用说明

使用方法 2016-07-16 DennisMi ChatForFun1&#xff0c;发送 #1 实现登陆&#xff0c;或者退出登陆 2&#xff0c;发送 #2 实现加入聊天&#xff0c;和退出聊天 3&#xff0c;聊天开始后&#xff0c;可以直接发送消息 4&#xff0c;如果需要退出登陆或者退出聊天&#xff0c;…

.NET 6新特性试用 | 总结:我最喜欢的5个特性

前言不知不觉&#xff0c;《.NET 6新特性试用》系列文章已经写了20多篇&#xff0c;而今天终于要告一段落了。如果你还没有看过&#xff0c;详细文章列表在这里&#xff1a;.NET 6新特性试用系列在这么多特性中&#xff0c;我最喜欢如下5个特性&#xff1a;1、最小Web API仅需三…

mikrotikROS系统的几种安装方法

这里简单介绍下几种ROS的安装方法,以及适用于哪些设备,这里我们先提供一个ROS6.0全系列版本的下载链接mikrotik-RouteOS-V6.0正式版下载 或者前往官方下载最新版常见的ROS硬件一般分为:X86架构(也是最常用的)mipsbe(欧米tik,部分RB系列,SXT,Groove等)mipsle(RBC系列,RB100,R…

分布式云+dubbo+zookeeper+Springmvc整合

2019独角兽企业重金招聘Python工程师标准>>> Dubbo采用全Spring配置方式&#xff0c;透明化接入应用&#xff0c;对应用没有任何API侵入&#xff0c;只需用Spring加载Dubbo的配置即可&#xff0c;Dubbo基于Spring的Schema扩展进行加载。 一&#xff1a;单机模式安装…

.Net下你不得不看的分表分库解决方案-多字段分片

介绍本期主角:ShardingCore 一款ef-core下高性能、轻量级针对分表分库读写分离的解决方案&#xff0c;具有零依赖、零学习成本、零业务代码入侵dotnet下唯一一款全自动分表,多字段分表框架,拥有高性能,零依赖、零学习成本、零业务代码入侵,并且支持读写分离动态分表分库,同一种…

知乎高赞:看懂这个颠覆世界观的认知,远比做1000道题更有用!

▲ 点击查看知乎上曾有个提问&#xff1a;“见过世面究竟有多重要&#xff1f;”其中一个点赞过万回答让无数网友产生共鸣&#xff1a;会讲究&#xff0c;能将就&#xff0c;能享受最好的&#xff0c;也能承受最坏的。见过世面的他们自然会在人群中散发不一样的气质&#xff0c…

WebBrowser!

WebBrowser! 原文:WebBrowser!我现在先放一些基础的文章在这里&#xff0c;以后再放别的上来官方范例连接http://www.microsoft.com/china/msdn/library/langtool/vcsharp/OvervwWebBrowExp.mspxQ&A 2005年5月21日 0:14:19 Q: 新键入的地址不能在新建好的窗口里打开:A:每…

Android USB Host与HID通讯(二)

2019独角兽企业重金招聘Python工程师标准>>> 原文出处&#xff1a;http://han21912.lofter.com/post/c3919_51401d 接上一篇&#xff1a;Android USB Host与HID通讯 (一) 从上篇已经可以枚举到HID设备&#xff0c;接下来看看寻找设备的接口和通信端点&#xff0c;…

CentOS7安装PHP5.6.23

为什么80%的码农都做不了架构师&#xff1f;>>> 美国时间2014年11月13日&#xff0c;PHP开发团队&#xff0c;在「PHP 5.6.3 is available&#xff5c;PHP: Hypertext Preprocessor」上公布了PHP5.6系的最新版本「PHP 5.6.3」。 在最新的版本5.6.3不仅修改了多个Bu…

为什么接吻需要闭眼睛?

1 你用上5G了吗&#xff1f;它已经用上了▼2 戴口罩的好处又增加了▼3 原来如此...▼4 哈哈哈哈▼5 露脐装的正确打开方式&#xff08;素材源于网络&#xff0c;侵删&#xff09;▼6 火鸡面到底有多辣▼7 孩子你要完了&#xff08;素材来源网络&#xff0c;侵删&#xff0…

最近要出绩效了

上周我们公司的绩效面谈全部结束了&#xff0c;每年到这个时间点就是打绩效的时候了&#xff0c;对于职场打工人来说绩效绝对是最重要的事情之一&#xff0c;原因也很简单&#xff1a;奖金、晋升、涨薪都和它有关系。比如下面这个美团员工在脉脉上的自曝就很凄凉&#xff1a;互…

从B 树、B+ 树、B* 树谈到R 树

作者&#xff1a;July、weedge、Frankie。编程艺术室出品。 说明&#xff1a;本文从B树开始谈起&#xff0c;然后论述B树、B*树&#xff0c;最后谈到R 树。其中B树、B树及B*树部分由weedge完成&#xff0c;R 树部分由Frankie完成&#xff0c;全文最终由July统稿修订完成。 出…