最新要闻
- “一日三次”的药 到底该怎么吃?你可能一直都错了
- 比亚迪百万豪车!实拍仰望U8原地掉头:这圈儿真圆
- 环球关注:微软Edge拯救低清老视频 秒变高清!三代N卡、A卡都能用
- 快看:棉锦防火布
- 男子高烧近41度 体温计贴脸狂飙:近期谨防甲流 病死率很高
- 老人捡到手机不会接听错过四十多通电话 最终成功归还
- 反诈老陈自曝2022年收入133万:缴税近40万 捐赠84万+
- 国家二级保护动物有哪些
- 快报:一手卖掉《古墓丽影》:SE宣布总裁松田洋介辞职
- 每日速看!纪念上映20周年:《指环王:王者无敌》将重映4小时加长版
- 理想L7本月开启交付 50万以内第二排舒适度最好的SUV
- 全球信息:AMD显卡驱动罕见Bug:Windows都给搞崩了
- 精彩看点:老牛嚼电线被击倒 网友:应该是母牛 因为公牛不漏电
- 环球看点!奥斯卡掌掴事件后续
- 婚变?前亚视高层与澳门名媛太太近一年未见
- 焦点播报:员工增长近万人!AMD去年研发支出同比大幅上涨
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
【热闻】Asp.net core mapcontrollers 背后干了些啥
1.背景
当我们在写webapi的时候我们发现,框架自动帮我们写好了 app.MapControllers(),看注释写的是帮我们将controllerl里面的action映射为我们的终结点,那具体是怎么弄得呢,我觉得可以仔细研究一下,看一下背后的逻辑.
2.开始研究,用dnspy看一下源码
public static ControllerActionEndpointConventionBuilder MapControllers(this IEndpointRouteBuilder endpoints){ //确保依赖的服务已经注册 可以进去看看帮我们注入了哪些东西,后面的代码可以看到它们身影ControllerEndpointRouteBuilderExtensions.EnsureControllerServices(endpoints);return ControllerEndpointRouteBuilderExtensions.GetOrCreateDataSource(endpoints).DefaultBuilder;}//接上面,创建endpoint数据源private static ControllerActionEndpointDataSource GetOrCreateDataSource(IEndpointRouteBuilder endpoints){ControllerActionEndpointDataSource controllerActionEndpointDataSource = endpoints.DataSources.OfType().FirstOrDefault();if (controllerActionEndpointDataSource == null){ //相关服务OrderedEndpointsSequenceProviderCache requiredService = endpoints.ServiceProvider.GetRequiredService(); //获取数据源controllerActionEndpointDataSource = endpoints.ServiceProvider.GetRequiredService().Create(requiredService.GetOrCreateOrderedEndpointsSequenceProvider(endpoints));endpoints.DataSources.Add(controllerActionEndpointDataSource);}return controllerActionEndpointDataSource;}
重点就是 ControllerActionEndpointDataSourceFactory.Create()函数帮我们构建数据源。
controllerActionEndpointDataSourceFactory
internal class ControllerActionEndpointDataSourceFactory { private readonly ControllerActionEndpointDataSourceIdProvider _dataSourceIdProvider; private readonly IActionDescriptorCollectionProvider _actions; private readonly ActionEndpointFactory _factory; public ControllerActionEndpointDataSourceFactory( ControllerActionEndpointDataSourceIdProvider dataSourceIdProvider, //这个很重要,为我们提供controller action的信息,具体实现类应该是 //ActionDescriptorCollectionProvider IActionDescriptorCollectionProvider actions, ActionEndpointFactory factory) { _dataSourceIdProvider = dataSourceIdProvider; _actions = actions; _factory = factory; } public ControllerActionEndpointDataSource Create(OrderedEndpointsSequenceProvider orderProvider) { //直接new一个 datasource return new ControllerActionEndpointDataSource(_dataSourceIdProvider, _actions, _factory, orderProvider); } }
终于看到我们的datascource了,所以进去自己看看,如果构建的endpoint.以及最终实现的类是哪个。直接点进去类,可以看到类的构造函数(没贴出来),实际上当我们第一次启动应用的时候,endpoint是没有构建出来的,直到第一次访问,才会进行初始化. 可以看到调用链 Initialize() =>UpdateEndpoints()=>CreateEndpoints()
(资料图片仅供参考)
internal abstract class ActionEndpointDataSourceBase : EndpointDataSource, IDisposable{ //获取endpoints public override IReadOnlyList Endpoints { get { Initialize(); return _endpoints; } } private void Initialize() { if (_endpoints == null) { lock (Lock) { if (_endpoints == null) { UpdateEndpoints(); } } } } private void UpdateEndpoints() { lock (Lock) { var endpoints = CreateEndpoints(_actions.ActionDescriptors.Items, Conventions); // See comments in DefaultActionDescriptorCollectionProvider. These steps are done // in a specific order to ensure callers always see a consistent state. // Step 1 - capture old token var oldCancellationTokenSource = _cancellationTokenSource; // Step 2 - update endpoints _endpoints = endpoints; // Step 3 - create new change token _cancellationTokenSource = new CancellationTokenSource(); _changeToken = new CancellationChangeToken(_cancellationTokenSource.Token); // Step 4 - trigger old token oldCancellationTokenSource?.Cancel(); } }}internal class ControllerActionEndpointDataSource:ActionEndpointDataSourceBase{ protected override List CreateEndpoints(IReadOnlyList actions, IReadOnlyList> conventions) { var endpoints = new List(); var keys = new HashSet(StringComparer.OrdinalIgnoreCase); // MVC guarantees that when two of it"s endpoints have the same route name they are //equivalent. // However, Endpoint Routing requires Endpoint Names to be unique. var routeNames = new HashSet(StringComparer.OrdinalIgnoreCase); // For each controller action - add the relevant endpoints. // 1. If the action is attribute routed, we use that information verbatim // 2. If the action is conventional routed // a. Create a *matching only* endpoint for each action X route (if possible) // b. Ignore link generation for now for (var i = 0; i < actions.Count; i++) { if (actions[i] is ControllerActionDescriptor action) { //逻辑重点,为每个action构建一个endpoint. _endpointFactory.AddEndpoints(endpoints, routeNames, action, _routes, conventions, CreateInertEndpoints); if (_routes.Count > 0) { // If we have conventional routes, keep track of the keys so we can create // the link generation routes later. foreach (var kvp in action.RouteValues) { keys.Add(kvp.Key); } } } } // Now create a *link generation only* endpoint for each route. This gives us a very // compatible experience to previous versions. for (var i = 0; i < _routes.Count; i++) { var route = _routes[i]; _endpointFactory.AddConventionalLinkGenerationRoute(endpoints, routeNames, keys, route, conventions); } return endpoints; }}
可以看到我们针对于每个action构建一个endpoint,AddEndpoints()所以继续进去看看逻辑。
public void AddEndpoints( List endpoints, HashSet routeNames,ActionDescriptor action,IReadOnlyList routes,IReadOnlyList> conventions, bool createInertEndpoints){ //不走的逻辑 代码被我省略删除 路由模板不为空。 if (action.AttributeRouteInfo?.Template != null){ //构建出来处理去请求的委托.很重要 var requestDelegate = CreateRequestDelegate(action) ?? _requestDelegate; //属性路由模板 var attributeRoutePattern = RoutePatternFactory.Parse(action.AttributeRouteInfo.Template); // Modify the route and required values to ensure required values can be successfully subsituted. // Subsitituting required values into an attribute route pattern should always succeed. var (resolvedRoutePattern, resolvedRouteValues) = ResolveDefaultsAndRequiredValues(action, attributeRoutePattern); var updatedRoutePattern = _routePatternTransformer.SubstituteRequiredValues(resolvedRoutePattern, resolvedRouteValues); //省略不重要代码 var builder = new RouteEndpointBuilder(requestDelegate, updatedRoutePattern, action.AttributeRouteInfo.Order) { DisplayName = action.DisplayName, };//添加action data到builder AddActionDataToBuilder( builder, routeNames, action, action.AttributeRouteInfo.Name, dataTokens: null, action.AttributeRouteInfo.SuppressLinkGeneration, action.AttributeRouteInfo.SuppressPathMatching, conventions, perRouteConventions: Array.Empty>()); endpoints.Add(builder.Build()); }}
CreateRequestDelegate可以看到构建处理器的逻辑,我们进去看看,由于是ioc注入的容器所以我们需要找到实现类。实现类是 ControllerRequestDelegateFactory类
ControllerRequestDelegateFactory
private RequestDelegate? CreateRequestDelegate(ActionDescriptor action, RouteValueDictionary? dataTokens = null) { foreach (var factory in _requestDelegateFactories) {//看来我们可以注入我们的处理器逻辑,需要注明一下顺序(或者是我记得后来注入的在最前面?) var requestDelegate = factory.CreateRequestDelegate(action, dataTokens); if (requestDelegate != null) { return requestDelegate; } } return null; }// ControllerRequestDelegateFactory方法public RequestDelegate? CreateRequestDelegate(ActionDescriptor actionDescriptor, RouteValueDictionary? dataTokens) { //省略不重要代码//针对于 context的委托.非常完美 return context => { RouteData routeData; if (dataTokens is null or { Count: 0 }) { routeData = new RouteData(context.Request.RouteValues); } else { routeData = new RouteData(); routeData.PushState(router: null, context.Request.RouteValues, dataTokens); } var actionContext = new ActionContext(context, routeData, actionDescriptor); var controllerContext = new ControllerContext(actionContext) { // PERF: These are rarely going to be changed, so let"s go copy-on-write. ValueProviderFactories = new CopyOnWriteList(_valueProviderFactories) }; controllerContext.ModelState.MaxAllowedErrors = _maxModelValidationErrors; //实际上这点很重要,这里是帮助我们构建controller类的,因为控制器类没有注入ioc容器 var (cacheEntry, filters) = _controllerActionInvokerCache.GetCachedResult(controllerContext); //很重要的一个东西,直接把我们引入到mvc的世界中,各种filter逻辑都在这 var invoker = new ControllerActionInvoker( _logger, _diagnosticListener, _actionContextAccessor, _mapper, controllerContext, cacheEntry, filters); return invoker.InvokeAsync(); }; }
看了半天找到了构建controller类的逻辑,那我们进去看看,既然没有注入到ioc,那么是如何构建的呢.进去getcacheResult中看看。
Controller类的生成逻辑
public (ControllerActionInvokerCacheEntry cacheEntry, IFilterMetadata[] filters) GetCachedResult(ControllerContext controllerContext) { var actionDescriptor = controllerContext.ActionDescriptor; // We don"t care about thread safety here if (cacheEntry is null) { //省略 部分代码 //这个是重点,实际上是一个委托,为我们生成controller,下面有代码 var controllerFactory =_controllerFactoryProvider.CreateControllerFactory(actionDescriptor); var controllerReleaser = _controllerFactoryProvider.CreateAsyncControllerReleaser(actionDescriptor); // 省略 部分代码 cacheEntry = new ControllerActionInvokerCacheEntry( filterFactoryResult.CacheableFilters, controllerFactory, controllerReleaser, propertyBinderFactory, objectMethodExecutor, actionMethodExecutor); actionDescriptor.CacheEntry = cacheEntry; } // 省略 ...... return (cacheEntry, filters); }
逻辑是一个provider构建委托生成的,注入的实现类是 ControllerFactoryProvider 看看逻辑
ControllerFactoryProvider
public Func CreateControllerFactory(ControllerActionDescriptor descriptor) { //省略 代码 var controllerType = descriptor.ControllerTypeInfo?.AsType(); if (_factoryCreateController != null) { //第一种逻辑 return _factoryCreateController; } var controllerActivator = _activatorProvider.CreateActivator(descriptor); var propertyActivators = GetPropertiesToActivate(descriptor); //第二种逻辑 object CreateController(ControllerContext controllerContext) { var controller = controllerActivator(controllerContext); for (var i = 0; i < propertyActivators.Length; i++) { var propertyActivator = propertyActivators[i]; propertyActivator(controllerContext, controller); } return controller; } return CreateController; }
返回生成controller类的委托有两种逻辑 ,实际上我们走的是第一种 即 _factoryCreateController ,它在构造的时候被初始化为 _factoryCreateController = controllerFactory.CreateController;controllerFactory类又是哪个类呢,实际上是我们注入的DefaultControllerFactory 类,很熟悉把,因为以前的版本也是这么做的
DefaultControllerFactory
public object CreateController(ControllerContext context) { //重点代码 var controller = _controllerActivator.Create(context); foreach (var propertyActivator in _propertyActivators) { propertyActivator.Activate(context, controller); } return controller; }
根据你的一个controllercontext生成我们的控制类,_controllerActivator的实现类实际上我们注入的是 DefaultControllerActivator,进去具体看看
DefaultControllerActivator
public object Create(ControllerContext controllerContext) { //核心代码 删除了一些代码 var controllerTypeInfo = controllerContext.ActionDescriptor.ControllerTypeInfo; var serviceProvider = controllerContext.HttpContext.RequestServices; return _typeActivatorCache.CreateInstance
引出了新的类 _typeActivatorCache ,这个类的注入实际上是 TypeActivatorCache
TypeActivatorCache
internal class TypeActivatorCache : ITypeActivatorCache { private readonly Func _createFactory = (type) => ActivatorUtilities.CreateFactory(type, Type.EmptyTypes); private readonly ConcurrentDictionary _typeActivatorCache = new ConcurrentDictionary(); /// public TInstance CreateInstance( IServiceProvider serviceProvider, Type implementationType) { //核心代码 其他代码删除 var createFactory = _typeActivatorCache.GetOrAdd(implementationType, _createFactory); return (TInstance)createFactory(serviceProvider, arguments: null); } }
那么生成controller的大佬终于出来了 ActivatorUtilities 是这个类 ,名字听着就霸气,进一步进去 结果看不到了,因为asp.net core的源码没有这部分。所以就在这停下吧 .如果你想更深入的了解不妨看看这篇文章,深入且详细 ASP.NET Core Controller与IOC的羁绊
controller类的生成总结
它不是托管到ioc的,而是通过其他的方式获取 ,获取逻辑:ControllerActionInvokerCache.GetCachedResult()=>ControllerFactoryProvider.CreateControllerFactory()=>DefaultControllerFactory.CreateController()=>DefaultControllerActivator.Create()=>TypeActivatorCache.CreateInstance()=>ActivatorUtilities.CreateFactory(type, Type.EmptyTypes);这个就是一步步的调用逻辑,不像我写逻辑,直接new一个完事
controller类的调用逻辑
上面知道了 controller源头从哪来,那现在就要寻找他的出生地。继续找逻辑.我们知道CreateRequestDelegate生成处理委托,这就是处理整个处理逻辑,返回了一个ControllerActionInvoker 。
var invoker = new ControllerActionInvoker( _logger, _diagnosticListener, _actionContextAccessor, _mapper, controllerContext, cacheEntry, filters); return invoker.InvokeAsync();
实际上是调用 InvokeAsync().这个就吊了,逻辑就涉及到我们的各种过滤器了.
ResourceInvoker
public virtual Task InvokeAsync() { _actionContextAccessor.ActionContext = _actionContext; var scope = _logger.ActionScope(_actionContext.ActionDescriptor); Task task; try { // 调用filter管道 task = InvokeFilterPipelineAsync(); } catch (Exception exception) { return Awaited(this, Task.FromException(exception), scope); } if (!task.IsCompletedSuccessfully) { return Awaited(this, task, scope); } static async Task Awaited(ResourceInvoker invoker, Task task, IDisposable? scope) { try { await task; } finally { await invoker.ReleaseResourcesCore(scope); } } }
InvokeFilterPipelineAsync
private Task InvokeFilterPipelineAsync() { var next = State.InvokeBegin; // The `scope` tells the `Next` method who the caller is, and what kind of state to initialize to // communicate a result. The outermost scope is `Scope.Invoker` and doesn"t require any type // of context or result other than throwing. var scope = Scope.Invoker; // The `state` is used for internal state handling during transitions between states. In practice this // means storing a filter instance in `state` and then retrieving it in the next state. var state = (object?)null; // `isCompleted` will be set to true when we"ve reached a terminal state. var isCompleted = false; try { while (!isCompleted) { var lastTask = Next(ref next, ref scope, ref state, ref isCompleted); if (!lastTask.IsCompletedSuccessfully) { return Awaited(this, lastTask, next, scope, state, isCompleted); } } return Task.CompletedTask; } catch (Exception ex) { // Wrap non task-wrapped exceptions in a Task, // as this isn"t done automatically since the method is not async. return Task.FromException(ex); } static async Task Awaited(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object? state, bool isCompleted) { await lastTask; while (!isCompleted) { await invoker.Next(ref next, ref scope, ref state, ref isCompleted); } } }
结合 next函数实用 (贴部分代码)
next函数
private Task Next(ref State next, ref Scope scope, ref object? state, ref bool isCompleted) { switch (next) { case State.InvokeBegin: { goto case State.AuthorizationBegin; } case State.AuthorizationBegin: { _cursor.Reset(); goto case State.AuthorizationNext; }//删除了一堆代码 case State.ActionBegin: { //实际上调用此代码 var task = InvokeInnerFilterAsync(); if (!task.IsCompletedSuccessfully) { next = State.ActionEnd; return task; } goto case State.ActionEnd; } case State.ActionEnd: { if (scope == Scope.Exception) { // If we"re inside an exception filter, let"s allow those filters to "unwind" before // the result. isCompleted = true; return Task.CompletedTask; } var task = InvokeResultFilters(); if (!task.IsCompletedSuccessfully) { next = State.ResourceInsideEnd; return task; } goto case State.ResourceInsideEnd; } case State.InvokeEnd: { isCompleted = true; return Task.CompletedTask; } default: throw new InvalidOperationException(); } }
可以看到上面的调用逻辑,实际上是状态机,指明下一步调用的函数和逻辑,然后直到完全完成任务,我们可以看到 当actionbegin开始的时候调用的任务是 InvokeInnerFilterAsync,可以点进去具体看看,具体类是ControllerActionInvoker
ControllerActionInvoker
protected override Task InvokeInnerFilterAsync() { try { var next = State.ActionBegin; var scope = Scope.Invoker; var state = (object?)null; var isCompleted = false; while (!isCompleted) { //重点代码 var lastTask = Next(ref next, ref scope, ref state, ref isCompleted); if (!lastTask.IsCompletedSuccessfully) { //返回task ,实际保证了内部逻辑执行的有序性。 return Awaited(this, lastTask, next, scope, state, isCompleted); } } return Task.CompletedTask; } static async Task Awaited(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, object? state, bool isCompleted) { //参数都是枚举,值类型 或者结构 这点很重要. await lastTask; while (!isCompleted) { await invoker.Next(ref next, ref scope, ref state, ref isCompleted); } } }private Task Next(ref State next, ref Scope scope, ref object? state, ref bool isCompleted) { switch (next) { case State.ActionBegin: { var controllerContext = _controllerContext; //游标指针归0,指向当前的filter位置. _cursor.Reset(); //调用了 委托生成 controller实例. 生成controller _instance = _cacheEntry.ControllerFactory(controllerContext); var task = BindArgumentsAsync(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ActionNext; return task; } goto case State.ActionNext; } // 如果filter调用完了,那么就进去到这个方法. case State.ActionInside: { //调用controller的action方法. var task = InvokeActionMethodAsync(); if (task.Status != TaskStatus.RanToCompletion) { next = State.ActionEnd; return task; } goto case State.ActionEnd; } } // 调用的具体方法 private Task InvokeActionMethodAsync() { // 保留了一些重要代码. var objectMethodExecutor = _cacheEntry.ObjectMethodExecutor; var actionMethodExecutor = _cacheEntry.ActionMethodExecutor; var orderedArguments = PrepareArguments(_arguments, objectMethodExecutor); //调用 controller action方法. var actionResultValueTask = actionMethodExecutor.Execute(_mapper, objectMethodExecutor, _instance!, orderedArguments); if (actionResultValueTask.IsCompletedSuccessfully) { _result = actionResultValueTask.Result; } else { return Awaited(this, actionResultValueTask); } return Task.CompletedTask; }
此时我们终于找到了 controller的调用逻辑链,同时我们也找到了 我们注册的过滤器在哪个位置被调用,它为我们揭开了神秘的面纱。invoker.InvokeAsync()=>InvokeFilterPipelineAsync()=>next() (状态机调用了我们注入的filter)=>InvokeActionMethodAsync()。
总结
做个总结,首先来说目标是想看看mapcontroller背后做了哪些事情,可以看到,它实际上给我们注册了endpoint数据源,通过endpointdatasourcefactory创建一个datasource(new 一个),实际上是我们为每一个action创建一个RouteEndpoint, 通过CreateRequestDelegate方法创建处理请求的委托,然后通过调用DefaultControllerFactory类为我们创建controller实例,并没有从ioc中获取,然后我们在我们在处理请求的时候,通过引入状态机的调用模式,将我们注入的filters来对请求进行先一步的处理,同时调用InvokeActionMethodAsync方法完成请求的处理。大概的逻辑就是这样。还有我们注入了endpointdatasource,所以才有userouting,useendpoint等进而注入一些重要的中间件,有兴趣的可以看看上一篇文章。总结的总结,对着源码找了一下调用的逻辑,以后写bug的时候更加得心应手了.
有兴趣可以看看以下文章
ASP.NET Core Controller与IOC的羁绊 .NET Core开发日志——Controller
-
【热闻】Asp.net core mapcontrollers 背后干了些啥
1 背景当我们在写webapi的时候我们发现,框架自动帮我们写好了app MapControllers(),看注释写的是帮我...
来源: -
当前关注:Mac OS 打开pycharm立即闪退,报错initial heap size set to a larger value than the max
电脑突然不能打开pycharm了,一打开就闪退,通过终端启动发现报错initialheapsizesettoalargervaluethanthemaximumheapsize
来源: 【热闻】Asp.net core mapcontrollers 背后干了些啥
思科交换机的密码策略与端口安全设置
当前关注:Mac OS 打开pycharm立即闪退,报错initial heap size set to a larger value than the max
“一日三次”的药 到底该怎么吃?你可能一直都错了
比亚迪百万豪车!实拍仰望U8原地掉头:这圈儿真圆
环球关注:微软Edge拯救低清老视频 秒变高清!三代N卡、A卡都能用
快看:棉锦防火布
环球即时看!EF7DbContext池
天天时讯:DotNet 5.0 部署 Docker 注意
男子高烧近41度 体温计贴脸狂飙:近期谨防甲流 病死率很高
老人捡到手机不会接听错过四十多通电话 最终成功归还
反诈老陈自曝2022年收入133万:缴税近40万 捐赠84万+
国家二级保护动物有哪些
任意Exe转ShellCode?
快报:一手卖掉《古墓丽影》:SE宣布总裁松田洋介辞职
每日速看!纪念上映20周年:《指环王:王者无敌》将重映4小时加长版
理想L7本月开启交付 50万以内第二排舒适度最好的SUV
全球信息:AMD显卡驱动罕见Bug:Windows都给搞崩了
精彩看点:老牛嚼电线被击倒 网友:应该是母牛 因为公牛不漏电
环球看点!奥斯卡掌掴事件后续
【读书】《成就上瘾:把成事当成一种习惯》
json转golang结构
婚变?前亚视高层与澳门名媛太太近一年未见
焦点播报:员工增长近万人!AMD去年研发支出同比大幅上涨
小米有品219元:平仄普洱生熟茶饼礼盒99元大促
每日热闻!胡令能是哪里人_胡令能简介
手工耿发明新刑具“忏悔辅助器”:让你的脑袋自动撞墙
世界观点:登陆Steam国区:暗黑Like游戏《火炬之光:无限》PC版或将手游同步推出
女子地铁上手机外放收“罚单” 南京地铁:车厢内禁喧哗
第六章 应用层
python文件的高级应用
1. 简单版
群晖NAS大促:四盘位DS420+历史低价
每日速看!Twitter被曝12月营收骤降40%:广告商抽身成主要原因
【全球播资讯】node.js学习技巧
速递!撑伞也是雨中人什么意思_撑伞也是雨中人这句话什么意思
Intel或将开发“视频DLSS”同款超分辨率技术:最低仅需10代酷睿
天天信息:MASA Framework源码解读-01 MASAFacotry工厂设计(一个接口多个实现的最佳姿势)
环球通讯!(数据库系统概论|王珊)第九章关系查询与关系优化:习题
天天看点:侠盗猎车手圣安地列斯攻略
每日热议!稳了!索尼PS4/PS5之父操刀新一代PS6主机:发布时间及首发大作曝光
当前消息!三星Galaxy S23 Ultra又出问题:S Pen被指出现随机断连
全球短讯!Codeforces 1785 E Infinite Game 题解 (图论,自动机,dp)
数字信号处理流程
播报:P8大佬的 62条SQL优化策略,太牛X了!! 收藏起来有大用!!!
学会了Java 8 Lambda表达式,简单而实用
天天最资讯丨修复 Ubuntu 中的 “Key is stored in legacy trusted.gpg keyring” 问题
数码相机卖不动:2023年1月销量大跌36%!单反惨烈
世界今日讯!长安深蓝全新中型SUV S7亮相:仪表盘“消失”
传大超转职普莱斯上尉
环球快播:美国一架飞机在飞行中突然强烈颠簸 竟致1人死亡
一口气58首歌 主办方因为周杰伦多唱被罚钱!周董回应:哥无所谓
环球热消息:抖店个体和企业开店费用_开店费用
世界关注:成都皮肤科医院排名第一_成都皮肤科医院qq
每日看点!硬挺不厚 穿着不热!放克纯棉T恤大促:20.1元包邮
售价13.99万元起 本田型格HATCHBACK正式上市
辣眼睛?网红“安福路小公主”首度回应质疑:给自己外貌打90分 对恶评不在意
【环球播资讯】(数据库系统概论|王珊)第九章关系查询处理和关系优化-第四节:查询优化之物理优化
直播电商名词解释
超百Gbps容量!中星26号卫星成功定点:我国自研卫星平台
全球微动态丨防缩水可机洗 GXG男士针织衫:89元手慢无
Java实战(第二版)读后总结与感想
201球!姆巴佩加冕队史射手王 24岁就成第一人 2.2亿投皇马?
日系车走下神坛?本田中国2月销量大跌三成 已连跌6月
世界看点:国家老年大学正式揭牌!超40万门课程 50周岁以上可以报名
全球自动驾驶公司排名公布 特斯拉再次垫底
环球看点!大熊猫走姿神似《狂飙》高启盛 动物园回应:走路“带风”性格豪放
人脸识别还要蹲车外看摄像头?小鹏致歉:已下架第三方应用
环球观速讯丨上汽奥迪员工内购价最高优惠16万 客服:若倒卖一查到底
当前消息!谈谈 WMTS 中的 TileMatrix 与 ScaleDenominator
当前滚动:《街霸6》嘉米伸懒腰 又一次引发网友二创热潮
全球今日讯!day01-项目介绍+SSM环境搭建
快讯:送你5款免费好玩的小游戏-搜嗖工具箱
世界热文:男子微波炉加热蛋白吃饭时爆炸 家属:很后怕 幸好还没吃进嘴里
焦点观察:95后考研落榜父母上岸疑似是营销旧文:当事人已删帖清号
今日精选:《狂飙》反派戏九成是香港导演拍摄 代表作《无间道》:网友惊叹
特斯拉召回3470辆汽车:广东又现失控连撞多车冲毁店门 潮州事故争议还在
天天观速讯丨资深教师称有学校已开始裁减英语老师:有专家称不支持取消英语主科地位建议
天天实时:黑曼巴科比还在吗_黑曼巴科比
当前头条:Paper Reading: How good are query optimizers, really?
全球实时:使用ELRepo升级CentOS内核
天天热点!使用招商银行云直连服务提现
新动态:TCP通信聊天服务端和客户端(C/C++语言开发)附完整源码
焦点信息:“学雷锋” 护平安
绝了!民间大神将手机魔改成30000mAh电池:续航BT、可两周一充
【环球报资讯】可算盼到!苹果一大波春季新品要来了:黄色款iPhone 14在列
全球观热点:二叉树遍历的操作与实现
神速!Android 15全球首曝:代号“香草冰淇淋”相当甜美
正直播:感动中国2022年度人物盛典!名单揭晓:满满正能量
全球热资讯!代表谈中传硕士在火锅店当保洁:建议大学生先就业再择业
简讯:库存多到爆!今年才两个月 SSD价格就跌超3成:还会更便宜?
环球热点!男子高速公路狂飙120km/h看《狂飙》:不碰方向盘、不看正前方
小米平板6系列来了:外形、CPU配置大曝光!确认新增NFC
焦点速读:真心恐怖!南极洲深海拍到罕见冥河水母:触手约10米长
【世界热闻】无/低代码开发平台(产品)
跳过中考、高考、研考!15岁女生被西交大少年班录取:8年本硕连读
单踏板模式害死人?广东一特斯拉疑失控连撞多车冲毁店门 两人受伤现场惨
The Missing Semester - 第五讲 学习笔记
记录--在Vue3这样子写页面更快更高效
全球今日讯!打开MASA Blazor的正确姿势5:插槽