刷手机网站关键词wordpress事例

news/2025/9/23 0:16:24/文章来源:
刷手机网站关键词,wordpress事例,安远网站制作,天津网站建设noakj前面的章节中#xff0c;我们从纯理论的角度对依赖注入进行了深入论述#xff0c;我们接下来会对.NET Core依赖注入框架进行单独介绍。为了让读者朋友能够更好地理解.NET Core依赖注入框架的设计与实现#xff0c;我们按照类似的原理创建了一个简易版本的依赖注入框架#… 前面的章节中我们从纯理论的角度对依赖注入进行了深入论述我们接下来会对.NET Core依赖注入框架进行单独介绍。为了让读者朋友能够更好地理解.NET Core依赖注入框架的设计与实现我们按照类似的原理创建了一个简易版本的依赖注入框架也就是我们在前面多次提及的Cat。源代码下载普通服务的注册与消费泛型服务的注册与消费多服务实例的提供服务实例的生命周期一、编程体验虽然我们对这个名为Cat的依赖注入框架进行了最大限度的简化但是与.NET Core框架内部使用的真实依赖注入框架相比Cat不仅采用了一致的设计而且几乎具备了后者所有的功能特性。为了让大家对Cat具有一个感官的认识我们先来演示一下如何利用它来提供我们所需的服务实例。作为依赖注入容器的Cat对象不仅仅作为服务实例的提供者它同时还需要维护着服务实例的生命周期。Cat提供了三种生命周期模式如果要了解它们之间的差异就必须对多个Cat之间的层次关系有充分的认识。一个代表依赖注入容器的Cat对象用来创建其他的Cat对象后者视前者为“父容器”所以多个Cat对象通过其“父子关系”维系一个树形层次化结构。不过这仅仅是一个逻辑结构而已实际上每个Cat对象只会按照下图所示的方式引用整棵树的根。在了解了多个Cat对象之间的关系之后对于三种预定义的生命周期模式就很好理解了。如下所示的Lifetime枚举代表着三种生命周期模式其中Transient代表容器针对每次服务请求都会创建一个新的服务实例而Self则是将提供服务实例保存在当前容器中它代表针对某个容器范围内的单例模式Root则是将每个容器提供的服务实例统一存放到根容器中所以该模式能够在多个“同根”容器范围内确保提供的服务是单例的。public enum Lifetime{ Root, Self, Transient}代表依赖注入容器的Cat对象之所以能够为我们提供所需服务实例其根本前提是相应的服务注册在此之前已经添加到容器之中。服务总是针对服务类型接口、抽象类或者具体类型进行注册Cat通过定义的扩展方法提供了如下三种注册方式。除了直接提供服务实例的形式外默认采用Root模式我们在注册服务的时候必须指定一个具体的生命周期模式。指定具体的实现类型。提供一个服务实例。指定一个创建服务实例的工厂。我们定义了如下的接口和对应的实现类型来演示针对Cat的服务注册。其中Foo、Bar、Baz和Gux分别实现了对应的接口IFoo、IBar、IBaz和IGux其中Gux类型上标注了一个MapToAttribute特性注册了与对应接口IGux之间的映射。为了反映Cat对服务实例生命周期的控制我们让它们派生于同一个基类Base。Base实现了IDisposable接口我们在其构造函数和实现的Dispose方法中输出相应的文本以确定对应的实例何时被创建和释放。我们还定义了一个泛型的接口IFoobarT1, T2和对应的实现类FoobarT1, T2来演示Cat针对泛型服务实例的提供。public interface IFoo {}public interface IBar {}public interface IBaz {} public interface IGux {}public interface IFoobarT1, T2 {}public class Base : IDisposable{public Base() Console.WriteLine($Instance of {GetType().Name} is created.);public void Dispose() Console.WriteLine($Instance of {GetType().Name} is disposed.);}public class Foo : Base, IFoo{ }public class Bar : Base, IBar{ }public class Baz : Base, IBaz{ } [MapTo(typeof(IGux), Lifetime.Root)]public class Gux : Base, IGux { }public class FoobarT1, T2: IFoobarT1,T2{public IFoo Foo { get; }public IBar Bar { get; }public Foobar(IFoo foo, IBar bar) { Foo foo; Bar bar; }}在如下所示的代码片段中我们创建了一个Cat对象并采用上面提到的方式针对接口IFoo、IBar和IBaz注册了对应的服务它们采用的生命周期模式分别为Transient、Self和Root。然后我们还调用了另一个将当前入口程序集作为参数的Register方法该方法会解析指定程序集中标注了MapToAttribute特性的类型并作相应的服务注册对于我们演示的程序来该方法会完成针对IGux/Gux类型的服务注册。接下来我们利用Cat对象创建了它的两个子容器并调用子容器的GetServiceT方法提供相应的服务实例。class Program{static void Main() {var root new Cat() .RegisterIFoo, Foo(Lifetime.Transient) .RegisterIBar(_ new Bar(), Lifetime.Self) .RegisterIBaz, Baz(Lifetime.Root) .Register(Assembly.GetEntryAssembly());var cat1 root.CreateChild();var cat2 root.CreateChild();void GetServicesTService(Cat cat) { cat.GetServiceTService(); cat.GetServiceTService(); } GetServicesIFoo(cat1); GetServicesIBar(cat1); GetServicesIBaz(cat1); GetServicesIGux(cat1); Console.WriteLine(); GetServicesIFoo(cat2); GetServicesIBar(cat2); GetServicesIBaz(cat2); GetServicesIGux(cat2); }}上面的程序运行之后会在控制台上输出如图3-7所示的结果输出的内容不仅表明Cat能够根据添加的服务注册提供对应类型的服务实例还体现了它对生命周期的控制。由于服务IFoo被注册为Transient服务所以Cat针对该接口的服务提供四次请求都会创建一个全新的Foo对象。IBar服务的生命周期模式为Self如果我们利用同一个Cat对象来提供对应的服务实例该Cat对象只会创建一个Bar对象所以整个过程中会创建两个Bar对象。IBaz和IGux服务采用Root生命周期所以具有同根的两个Cat对象提供的总是同一个Baz/Gux对象后者只会被创建一次。除了提供类似于IFoo、IBar和IBaz这样非泛型的服务实例之外如果具有针对泛型定义Generic Definition的服务注册Cat同样也能提供泛型服务实例。如下面的代码片段所示在为创建的Cat对象添加了针对IFoo和IBar接口的服务注册之后我们调用Register方法注册了针对泛型定义IFoobar,的服务注册具体的实现类型为Foobar,。当我们利用Cat对象提供一个类型为IFoobarIFoo, IBar的服务实例的时候它会创建并返回一个FoobarFoo, Bar对象。public class Program{public static void Main() {var cat new Cat() .RegisterIFoo, Foo(Lifetime.Transient) .RegisterIBar, Bar(Lifetime.Transient) .Register(typeof(IFoobar,), typeof(Foobar,), Lifetime.Transient);var foobar (FoobarIFoo, IBar)cat.GetServiceIFoobarIFoo, IBar(); Debug.Assert(foobar.Foo is Foo); Debug.Assert(foobar.Bar is Bar); }}当我们在进行服务注册的时候可以为同一个类型添加多个服务注册。虽然添加的所有服务注册均是有效的不过由于扩展方法GetServiceTService总是返回一个唯一的服务实例我们对该方法采用了“后来居上”的策略即总是采用最近添加的服务注册来创建服务实例。如果我们调用另一个扩展方法GetServicesTService它将利用返回根据所有服务注册提供的服务实例。如下面的代码片段所示我们为创建的Cat对象添加了三个针对Base类型的服务注册对应的实现类型分别为Foo、Bar和Baz。我们最后将Base作为泛型参数调用了GetServicesBase方法该方法会返回包含三个Base对象的集合集合元素的类型分别为Foo、Bar和Baz。public class Program{public static void Main() {var services new Cat() .RegisterBase, Foo(Lifetime.Transient) .RegisterBase, Bar(Lifetime.Transient) .RegisterBase, Baz(Lifetime.Transient) .GetServicesBase(); Debug.Assert(services.OfTypeFoo().Any()); Debug.Assert(services.OfTypeBar().Any()); Debug.Assert(services.OfTypeBaz().Any()); }}如果提供的服务实例实现了IDisposable接口我们应该在适当的时候调用其Dispose方法释放该服务实例。由于服务实例的生命周期完全由作为依赖注入容器的Cat对象来管理那么通过调用Dispose方法来释放服务实例自然也应该由它来负责。Cat针对提供服务实例的释放策略取决于采用的生命周期模式具体的策略如下Transient和Self所有实现了IDisposable接口的服务实例会被当前Cat对象保存起来当Cat对象自身的Dispose方法被调用的时候这些服务实例的Dispose方法会随之被调用。Root由于服务实例保存在作为根容器的Cat对象上所以当这个Cat对象的Dispose方法被调用的时候这些服务实例的Dispose方法会随之被调用。上述的释放策略可以通过如下的演示实例来印证。我们在如下的代码片段中创建了一个Cat对象并添加了相应的服务注册。我们接下来调用了CreateChild方法创建代表子容器的Cat对象并用它提供了四个注册服务对应的实例。class Program{static void Main() {using (var root new Cat() .RegisterIFoo, Foo(Lifetime.Transient) .RegisterIBar(_ new Bar(), Lifetime.Self) .RegisterIBaz, Baz(Lifetime.Root) .Register(Assembly.GetEntryAssembly())) {using (var cat root.CreateChild()) { cat.GetServiceIFoo(); cat.GetServiceIBar(); cat.GetServiceIBaz(); cat.GetServiceIGux(); Console.WriteLine(Child cat is disposed.); } Console.WriteLine(Root cat is disposed.); } }}由于两个Cat对象的创建都是在using块中进行的所以它们的Dispose方法都会在using块结束的地方被调用。为了确定方法被调用的时机我们特意在控制台上打印了相应的文字。该程序运行之后会在控制台上输出如下图所示的结果我们可以看到当作为子容器的Cat对象的Dispose方法被调用的时候由它提供的两个生命周期模式分别为Transient和Self的两个服务实例Foo和Bar被正常释放了。至于生命周期模式为Root的服务实例Baz和Gux它的Dispose方法会延迟到作为根容器的Cat对象的Dispose方法被调用的时候。二、设计与实现在完成针对Cat的编程体验之后我们来聊聊这个依赖注入容器的设计原理和具体实现。由于作为依赖注入容器的Cat对象总是利用预先添加的服务注册来提供对应的服务实例所以服务注册至关重要。如下所示的就是表示服务注册的ServiceRegistry的定义它具有三个核心属性ServiceType、Lifetime和Factory分别代表服务类型、生命周期模式和用来创建服务实例的工厂。最终用来创建服务实例的工厂体现为一个类型为FuncCat,Type[], object的委托对象它的两个输入分别代表当前使用的Cat对象以及提供服务类型的泛型参数如果提供的服务类型并不是一个泛型类型这个参数被会指定为一个空的数组。public class ServiceRegistry{public Type ServiceType { get; }public Lifetime Lifetime { get; }public FuncCat,Type[], object actory { get; }internal ServiceRegistry Next { get; set; }public ServiceRegistry(Type serviceType, Lifetime lifetime, FuncCat,Type[], object factory) { ServiceType serviceType; Lifetime lifetime; Factory factory; }internal IEnumerableServiceRegistry AsEnumerable() {var list new ListServiceRegistry();for (var self this; self!null; self self.Next) { list.Add(self); }return list; }}我们将针对同一个服务类型ServiceType属性相同的多个ServiceRegistry组成一个链表作为相邻节点的两个ServiceRegistry对象通过Next属性关联起来。我们为ServiceRegistry定义了一个AsEnumerable方法使它返回由当前以及后续节点组成的ServiceRegistry集合。如果当前ServiceRegistry为链表头那么这个方法会返回链表上的所有ServiceRegistry对象。下图体现了服务注册核心三要素和链表结构。在了解了表示服务注册的ServiceRegistry之后我们来着重介绍表示依赖注入容器的Cat类型。如下面的代码片段所示Cat同时实现了IServiceProvider和IDisposable接口定义在前者中的GetService方法用于提供服务实例。作为根容器的Cat对象通过公共构造函数创建另一个内部构造函数则用来创建作为子容器的Cat对象指定的Cat对象将作为父容器。public class Cat : IServiceProvider, IDisposable{internal readonly Cat _root;internal readonly ConcurrentDictionaryType, ServiceRegistry _registries;private readonly ConcurrentDictionaryKey, object _services;private readonly ConcurrentBagIDisposable _disposables;private volatile bool _disposed;public Cat() { _registries new ConcurrentDictionaryType, ServiceRegistry(); _root this; _services new ConcurrentDictionaryKey, object(); _disposables new ConcurrentBagIDisposable(); }internal Cat(Cat parent) { _root parent._root; _registries _root._registries; _services new ConcurrentDictionaryKey, object(); _disposables new ConcurrentBagIDisposable(); }private void EnsureNotDisposed() {if (_disposed) {throw new ObjectDisposedException(Cat); } } ...}作为根容器的Cat对象通过_root字段表示。_registries字段返回的ConcurrentDictionaryType, ServiceRegistry对象用来存储所有添加的服务注册该字典对象的Key和Value分别表示服务类型和ServiceRegistry链表下图体现这一映射关系。由于需要负责完成对提供服务实例的释放工作所以我们需要将实现了IDisposable接口的服务实例保存在通过_disposables字段表示的集合中。由当前Cat对象提供的非Transient服务实例保存在由_services字段表示的一个ConcurrentDictionaryKey, object对象上该字典对象的键类型为如下所示的Key它相当于是创建服务实例所使用的ServiceRegistry对象和泛型参数类型数组的组合。internal class Key : IEquatableKey{public ServiceRegistry Registry { get; }public Type[] GenericArguments { get; }public Key(ServiceRegistry registry, Type[] genericArguments) { Registry registry; GenericArguments genericArguments; }public bool Equals(Key other) {if (Registry ! other.Registry) {return false; }if (GenericArguments.Length ! other.GenericArguments.Length) {return false; }for (int index 0; index GenericArguments.Length; index) {if (GenericArguments[index] ! other.GenericArguments[index]) {return false; } }return true; }public override int GetHashCode() {var hashCode Registry.GetHashCode();for (int index 0; index GenericArguments.Length; index) { hashCode ^ GenericArguments[index].GetHashCode(); }return hashCode; }public override bool Equals(object obj) obj is Key key ? Equals(key) : false;}虽然我们为Cat定义了若干扩展方法来提供多种不同的服务注册但是这些方法最终都会调用如下这个Register方法该方法会将提供的ServiceRegistry添加到_registries字段表示的字典对象中。值得注意的是不论我们是调用哪个Cat对象的Register方法指定的ServiceRegistry都会被添加到作为根容器的Cat对象上。public class Cat : IServiceProvider, IDisposable{public Cat Register(ServiceRegistry registry) { EnsureNotDisposed();if (_registries.TryGetValue(registry.ServiceType, out var existing)) { _registries[registry.ServiceType] registry; registry.Next existing; }else { _registries[registry.ServiceType] registry; }return this; } ...}用来提供服务实例的核心操作实现在如下这个GetServiceCore方法中。如下面的代码片段所示我们在调用该方法的时候需要指定对应的ServiceRegistry对象的服务类型的泛型参数。当该方法被执行的时候对于Transient的生命周期模式它会直接利用ServiceRegistry提供的工厂来创建服务实例。如果服务实例的类型实现了IDisposable接口该对象会被添加到_disposables字段表示的待释放服务实例列表中。对于Root和Self生命周期模式该方法会先根据提供的ServiceRegistry判断是否对应的服务实例已经存在存在的服务实例会直接返回。public class Cat : IServiceProvider, IDisposable{private object GetServiceCore(ServiceRegistry registry, Type[] genericArguments) {var key new Key(registry, genericArguments);var serviceType registry.ServiceType;switch (registry.Lifetime) {case Lifetime.Root: return GetOrCreate(_root._services, _root._disposables);case Lifetime.Self: return GetOrCreate(_services, _disposables);default: {var service registry.Factory(this, genericArguments);if (service is IDisposable disposable disposable ! this) { _disposables.Add(disposable); }return service; } }object GetOrCreate(ConcurrentDictionaryKey, object services, ConcurrentBagIDisposable disposables) {if (services.TryGetValue(key, out var service)) {return service; } service registry.Factory(this, genericArguments); services[key] service;if (service is IDisposable disposable) { disposables.Add(disposable); }return service; } }}GetServiceCore方法只有在指定ServiceRegistry对应的服务实例不存在的情况下才会利用提供的工厂来创建服务实例创建的服务实例会根据生命周期模式保存到作为根容器的Cat对象或者当前Cat对象上。如果提供的服务实例实现了IDisposable接口在采用Root生命周期模式下会被保存到作为根容器的Cat对象的待释放列表中。如果生命周期模式为Self它会被添加到当前Cat对象的待释放列表中。在实现的GetService方法中Cat会根据指定的服务类型找到对应的ServiceRegistry对象并最终调用GetServiceCore方法来提供对应的服务实例。GetService方法还会解决一些特殊服务的提供问题比如若服务类型为Cat或者IServiceProvider该方法返回的就是它自己。如果服务类型为IEnumerableTGetService方法会根据泛型参数类型T找到所有的ServiceRegistry并利用它们来创建对应的服务实例最终返回的是由这些服务实例组成的集合。除了这些针对泛型服务实例的提供也是在这个方法中解决的。public class Cat : IServiceProvider, IDisposable{public object GetService(Type serviceType) { EnsureNotDisposed();if (serviceType typeof(Cat) || serviceType typeof(IServiceProvider)) {return this; } ServiceRegistry registry;//IEnumerableTif (serviceType.IsGenericType serviceType.GetGenericTypeDefinition() typeof(IEnumerable)) {var elementType serviceType.GetGenericArguments()[0];if (!_registries.TryGetValue(elementType, out registry)) {return Array.CreateInstance(elementType, 0); }var registries registry.AsEnumerable();var services registries.Select(it GetServiceCore(it, Type.EmptyTypes)).ToArray(); Array array Array.CreateInstance(elementType, services.Length); services.CopyTo(array, 0);return array; }//Genericif (serviceType.IsGenericType !_registries.ContainsKey(serviceType)) {var definition serviceType.GetGenericTypeDefinition();return _registries.TryGetValue(definition, out registry)? GetServiceCore(registry, serviceType.GetGenericArguments()) : null; }//Normalreturn _registries.TryGetValue(serviceType, out registry)? GetServiceCore(registry, new Type[0]) : null; } ...}在实现的Dispose方法中由于所有待释放的服务实例已经保存到_disposables字段表示的集合中所以我们只需要依次调用它们的Dispose方法即可。在释放了所有服务实例并清空待释放列表后Dispose还会清空_services字段表示的服务实例列表。public class Cat : IServiceProvider, IDisposable{public void Dispose() { _disposed true;foreach(var disposable in _disposables) { disposable.Dispose(); } _disposables.Clear(); _services.Clear(); } ...}三、扩展方法为了方便注册服务我们定义了如下六个Register扩展方法。由于服务注册的添加总是需要调用Cat自身的Register方法来完成所以这些方法最终都需要创建一个代表服务注册的ServiceRegistry对象。对于一个ServiceRegistry对象来说它最为核心的元素莫过于表示服务实例创建工厂的FuncCat,Type[], object对象所以上述这六个扩展方法需要解决的就是创建这么一个委托对象。public static class CatExtensions{public static Cat Register(this Cat cat, Type from, Type to, Lifetime lifetime) { FuncCat, Type[], object factory (_, arguments) Create(_, to, arguments); cat.Register(new ServiceRegistry(from, lifetime, factory));return cat; }public static Cat RegisterTFrom, TTo(this Cat cat, Lifetime lifetime) where TTo:TFrom cat. Register(typeof(TFrom), typeof(TTo), lifetime);public static Cat Register(this Cat cat, Type serviceType, object instance) { FuncCat, Type[], object factory (_, arguments) instance; cat.Register(new ServiceRegistry(serviceType, Lifetime.Root, factory));return cat; }public static Cat RegisterTService(this Cat cat, TService instance) { FuncCat, Type[], object factory (_, arguments) instance; cat.Register(new ServiceRegistry(typeof(TService), Lifetime.Root, factory));return cat; }public static Cat Register(this Cat cat, Type serviceType, FuncCat, object factory, Lifetime lifetime) { cat.Register(new ServiceRegistry(serviceType, lifetime, (_, arguments) factory(_)));return cat; }public static Cat RegisterTService(this Cat cat, FuncCat,TService factory, Lifetime lifetime) { cat.Register(new ServiceRegistry(typeof(TService), lifetime, (_,arguments)factory(_)));return cat; }private static object Create(Cat cat, Type type, Type[] genericArguments) {if (genericArguments.Length 0) { type type.MakeGenericType(genericArguments); }var constructors type.GetConstructors();if (constructors.Length 0) {throw new InvalidOperationException($Cannot create the instance of {type} which does not have a public constructor.); }var constructor constructors.FirstOrDefault(it it.GetCustomAttributes(false).OfTypeInjectionAttribute().Any()); constructor ?? constructors.First();var parameters constructor.GetParameters();if (parameters.Length 0) {return Activator.CreateInstance(type); }var arguments new object[parameters.Length];for (int index 0; index arguments.Length; index) { arguments[index] cat.GetService(parameters[index].ParameterType); }return constructor.Invoke(arguments); }}由于前两个重载指定的是服务实现类型所以我们需要调用对应的构造函数来创建服务实例这一逻辑实现在私有的Create方法中。第三个扩展方法指定的直接就是服务实例所以我们很容易将提供的参数转换成一个FuncCat,Type[], object。我们刻意简化了构造函数的筛选逻辑。为了解决构造函数的选择问题我们引入如下这个InjectionAttribute特性。我们将所有公共实例构造函数作为候选的构造函数并会优先选择标注了该特性的构造函数。当构造函数被选择出来后我们需要通过分析其参数类型并利用Cat对象来提供具体的参数值这实际上是一个递归的过程。最终我们将针对构造函数的调用转换成FuncCat,Type[], object对象进而创建出表示服务注册的ServiceRegistry对象。[AttributeUsage( AttributeTargets.Constructor)]public class InjectionAttribute: Attribute {}前面给出的代码片段还提供了HasRegistry和HasRegistryT方法来确定指定类型的服务注册是否存在。除此之外用于提供服务实例的泛型方法GetServiceT和用于提供所有指定类型服务实例的GetServicesTService方法采用了如下的定义方式。public static class CatExtensions{public static IEnumerableTService GetServicesT(this Cat cat) cat.GetServiceIEnumerableTService ();public static TService GetServiceTService (this Cat cat) (TService)cat.GetService(typeof(T));}上述六个扩展方法帮助我们完成针对单一服务的注册有时间我们的项目中可能会出现非常多的服务需要注册如何能够完成针对它们的批量注册会是不错的选择。我们的依赖注入框架提供了针对程序集范围的批量服务注册。为了标识带注册的服务我们需要在服务实现类型上标注如下这个MapToAttribute类型并指定服务类型一般为它实现的接口或者继承的基类和生命周期。[AttributeUsage( AttributeTargets.Class, AllowMultiple true)]public sealed class MapToAttribute: Attribute{ public Type ServiceType { get; }public Lifetime Lifetime { get; }public MapToAttribute(Type serviceType, Lifetime lifetime) { ServiceType serviceType; Lifetime lifetime; }}针对程序集范围的批量服务注册实现在Cat的如下这个Register扩展方法中。如下面的代码片段所示该方法会从指定程序集中获取所有标注了MapToAttribute特性的类型并提取出服务类型、实现类型和生命周期模型然后利用它们批量完成所需的服务注册。public static class CatExtensions{ public static Cat Register(this Cat cat, Assembly assembly) {var typedAttributes from type in assembly.GetExportedTypes() let attribute type.GetCustomAttributeMapToAttribute()where attribute ! nullselect new { ServiceType type, Attribute attribute };foreach (var typedAttribute in typedAttributes) { cat.Register(typedAttribute.Attribute.ServiceType, typedAttribute.ServiceType, typedAttribute.Attribute.Lifetime); }return cat; }}除了上述这七个用来注册服务的Register扩展方法我们还为Cat类型定义了如下两个扩展方法其中CreateServiceT方法以泛型参数的形式指定获取服务实例对应注册的类型CreateServicesT方法会提供指定服务类型的所有实例而CreateChild方法则帮助我们创建一个代表子容器的Cat对象。public static class CatExtensions{ public static T GetServiceT(this Cat cat) (T)cat.GetService(typeof(T));public static IEnumerableT GetServicesT(this Cat cat) cat.GetServiceIEnumerableT();public static Cat CreateChild(this Cat cat) new Cat(cat);}

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

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

相关文章

网站上的图片带店面是怎么做的谷歌手机版下载安装

1什么是json JSON(JavaScript Object Notation,JS对象简谱)是一种轻量级的数据交换格式。它是基于ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰…

做电商有那个网站遵义企业网站建设

认识视图 视图是一个虚拟表,其内容由查询定义。同真实表一样,视图包含一系列带有名称的列和行数据,但视图并不是数据库真实存储的数据表。 视图是从一个、多个表或者视图中导出的表,包含一系列带有名称的数据列和若干条数据行。…

做暧小视频免费视频在线观看网站公司网站做的好的

awk从放弃到入门(11):拾遗之”三元运算”与”打印奇偶行” 三元运算打印奇偶行 本博文转载自 这篇文章中的知识点是建立在前文的基础上的,如果你还没有掌握前文中的知识,请先参考之前的文章。 这篇文章其实是对之前知…

河南郑州建网站公司建筑网站案例

MySQL-Front是一款实用的MYSQL数据库管理工具,软件自带了简体中文语言,与mysql数据库连接后就可以对其地蚝各类管理操作了,比如对域进行编辑、增加和删除,执行sql脚本或者导出数据库等操作,除此之外还可以将数据库保存…

可以自己设计一个公司的网站苏州电子商务网站建设

select ROUND(12.555, 2) --12.560 select cast(12.5550 as decimal(10,2)) --12.56 转载于:https://www.cnblogs.com/kedarui/p/3791337.html

带做网站上海房产交易网站

如果没有数据存在,如何将数组值设置为null?PHP数组设置空值以下是我的PHP阵列和我JSON编码 -{"title":"Impalz-Marketing","type":"Business Details","version":"1.0","login":…

网站建设班级通讯录如何做网页推广

一.数字孪生体技术概述 数字孪生体技术是跨层级,跨尺度的现实世界和虚拟世界的建立沟通的桥梁,是第四次工业革命的通用目的技术和核心技术体系之一,是支撑万物互联的综合技术系统,是数字经济发展的基础,是未来智能时代…

许昌住房和城乡建设部网站京津冀协同发展现状

有一天,您遇到一些代码,并认为这很漂亮,为什么我没有想到呢? 因此,我的长期同事Mark Warner在使用方法引用处理从String进行转换的标准名称/值存储模式方面有一个不错的选择。 int size store.getProperty("cac…

网站备案通管局门户网站是如何盈利的

应用场景: 电脑连接VPN之后,Java程序无法连接远程服务,比如第三方接口、远程数据库连接、远程微服务等。我个人遇到的情况有连接海康威视SDK,influxdb以及一些微服务。 解决办法: 启动Java时加入参数:-D…

为什么 TCP 是3次握手4次挥手?

为什么 TCP 是3次握手4次挥手?① 为什么是三次握手?(A: 客户端,B: 服务器) TCP连接是全双工的,意味着数据在两个方向上可以同时传输。因此,建立连接的关键是确保双方都具有发送和接收的能力,并且要同步双方的初…

烟台网站关键词推广深圳哪些建设公司招聘

像Eclipse这样的现代IDE提供了各种插件来简化Web开发。 但是,我相信将Tomcat作为“常规” Java应用程序启动仍然可以提供最佳的调试体验。 大多数情况下,这是因为这些工具将Tomcat或任何其他servlet容器作为外部进程启动,然后在其上附加一个远…

网站流量工具网站换了域名怎么查

LabVIEW绘制带有多个不同标尺的波形图 通过在同一波形图上使用多个轴,可以使用不同的标尺绘制数据。请按照以下步骤操作。 将波形图或图表控件放在前面板上。 1. 右键点击您要创建多个标尺的轴,然后选择复制标尺。例如,如果要为一个…

如何建立网站后台云商网站建设

cocos2d-x自带了不少示例,以及几个比较简单的游戏,不过这些游戏都是用javascript binding(SpiderMonkey)做的,所以我猜测javascript binding可能是cocos2d-x开发游戏的主流模式,优点是: 游戏逻辑用javascript&#xff…

企业网站ui模板下载如何改wordpress文章模板

原作者链接:基于卷积神经网络的中药识别(pytorch框架)【python源码UI界面前端界面功能源码详解】_识别中药python-CSDN博客 //gitcode,gitee,飞桨,csdn,bilibili。几个有用网站,直接搜索即可,平…

win7iis如何做网站广东东莞自己建站教程

1.用户好不容易一个工程的应力分析计算通过,不料,第二天使用时提示以下信息,对用户来说简直如同噩梦降临。 分析:要么用户移动了文件,要么用户删除了文件,用户两者都否定。无论怎么样文件不会莫名不见了&am…

青岛专业公司网站设计网站程序建设

P3356 火星探险问题 对于一个第一次经过会有价值,但是之后经过没有价值的点,我们的处理方法就是只连一条流量为1并且有费用的边,再连接流量为INF但是没有费用的边,这样我们要使得价值最大就会优先流有费用的边。

源码出售网站wordpress滑动验证码

第一招、mysql服务的启动和停止net stop mysqlnet start mysql第二招、登陆mysql语法如下: mysql -u用户名 -p用户密码键入命令mysql -uroot -p, 回车后提示你输入密码,输入12345,然后回车即可进入到mysql中了,mysql的…

java中的浮点数计算

在java语言中无法精确计算浮点数,例如: float a1,a2; System.out.println("请输入两个浮点数:"); Scanner sc=new Scanner(System.in); a1=sc.nextFloat(); a2=sc.nextFloat(); System.out.println("…

高端酒店网站模板经验推广

一、需求场景:每天固定时间执行某个行为/动作。 一开始想用定时器,后来无意间发现了这个插件,感觉功能太强大了,完美解决了我的问题。 二、下载地址:https://www.quartz-scheduler.net/ 也可以在项目中直接使用nugut进…

XYCTF2025复现(WEB)

ez_puzzle 打开环境也是发现个神奇的东西这里只要按键盘上的按键就会弹出这个 还有右键也不行 还有一个看源代码的方法,直接在网页里面输入,不过这个要在访问这个界面之前输入就是一个禁止键盘按键和鼠标右键的代码 …