Xamarin版的C# SVG路径解析器

简介: 原文:Xamarin版的C# SVG路径解析器 Xamarin版的C# SVG路径解析器,对SVG的Path路径进行解析,其中包括:主程序SvgPathParser.cs, 相关接口定义:ISourceFormatter.cs, 辅助类:FormatterRocks.cs, 从接口派生的CSharpCoreGraphicsFormatter.cs。
原文: Xamarin版的C# SVG路径解析器

Xamarin版的C# SVG路径解析器,对SVG的Path路径进行解析,其中包括:

主程序SvgPathParser.cs,

相关接口定义:ISourceFormatter.cs,

辅助类:FormatterRocks.cs,

从接口派生的CSharpCoreGraphicsFormatter.cs。


//主程序SvgPathParser.cs:

// Authors:
//    Sebastien Pouliot  <sebastien@xamarin.com>
//
// Copyright 2012-2013 Xamarin Inc.
//
// This file is mostly based on the C++ code from once magnificent Moonlight
// https://github.com/mono/moon/blob/master/src/xaml.cpp
// Copyright 2007 Novell, Inc. (http://www.novell.com)
//
// Licensed under the GNU LGPL 2 license only (no "later versions")

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;

namespace Poupou.SvgPathConverter {

    public class SvgPathParser {

        static int i;

        public ISourceFormatter Formatter { get; set; }

        public void Parse (string svgPath, string name = null)
        {
            if (Formatter == null)
                throw new InvalidOperationException ("Missing formatter");

            if (name == null)
                name = "Unnamed_" + (++i).ToString ();

            Parse (svgPath, name, Formatter);
        }

        static void Advance (string s, ref int pos)
        {
            if (pos >= s.Length)
                return;
            char c = s [pos];
            while (!Char.IsLetterOrDigit (c) && c != '.' && c!= '-' && c != '+') {
                if (++pos == s.Length)
                    return;
                c = s [pos];
            }
        }
        
        static int FindNonFloat (string s, int pos)
        {
            char c = s [pos];
            while ((Char.IsNumber (c) || c == '.' || c == '-' || c == '+')) {
                if (++pos == s.Length)
                    return pos;
                c = s [pos];
            }
            return pos;
        }
        
        static bool MorePointsAvailable (string s, int pos)
        {
            if (pos >= s.Length)
                return false;
            char c = s [pos];
            while (Char.IsWhiteSpace (c) || c == ',')
                c = s [++pos];
            return Char.IsDigit (c) || c == '.' || c == '-' || c == '+';
        }
        
        static float GetFloat (string svg, ref int pos)
        {
            int end = FindNonFloat (svg, pos);
            string s = svg.Substring (pos, end - pos);
            float f = Single.Parse (s, CultureInfo.InvariantCulture);
            pos = end;
            return f;
        }
        
        static PointF GetPoint (string svg, ref int pos)
        {
            while (Char.IsWhiteSpace (svg [pos]))
                pos++;
            float x = GetFloat (svg, ref pos);
            
            while (Char.IsWhiteSpace (svg [pos]))
                pos++;
            if (svg [pos] == ',')
                pos++;
            while (Char.IsWhiteSpace (svg [pos]))
                pos++;
            
            float y = GetFloat (svg, ref pos);
            
            return new PointF (x, y);
        }
        
        static PointF MakeRelative (PointF c, PointF m)
        {
            return new PointF (m.X + c.X, m.Y + c.Y);
        }

        static void Parse (string svg, string name, ISourceFormatter formatter)
        {
            formatter.Prologue (name);
            
            PointF start;
            PointF cp = new PointF (0, 0);
            PointF cp1, cp2, cp3;
            PointF qbzp, cbzp;
            int fill_rule = 0;
            int pos = 0;
            bool cbz = false;
            bool qbz = false;
            while (pos < svg.Length) {
                char c = svg [pos++];
                if (Char.IsWhiteSpace (c))
                    continue;
                
                bool relative = false;
                switch (c) {
                case 'f':
                case 'F':
                    c = svg [pos++];
                    if (c == '0')
                        fill_rule = 0;
                    else if (c == '1')
                        fill_rule = 1;
                    else
                        throw new FormatException ();
                    break;
                case 'h':
                    relative = true;
                    goto case 'H';
                case 'H':
                    float x = GetFloat (svg, ref pos);
                    if (relative)
                        x += cp.X;
                    cp = new PointF (x, cp.Y);
                    formatter.LineTo (cp);
                    cbz = qbz = false;
                    break;
                case 'm':
                    relative = true;
                    goto case 'M';
                case 'M':
                    cp1 = GetPoint (svg, ref pos);
                    if (relative)
                        cp1 = MakeRelative (cp, cp1);
                    formatter.MoveTo (cp1);
                    
                    start = cp = cp1;
                    
                    Advance (svg, ref pos);
                    while (MorePointsAvailable (svg, pos)) {
                        cp1 = GetPoint (svg, ref pos);
                        if (relative)
                            cp1 = MakeRelative (cp, cp1);
                        formatter.LineTo (cp1);
                    }
                    cp = cp1;
                    cbz = qbz = false;
                    break;
                case 'l':
                    relative = true;
                    goto case 'L';
                case 'L':
                    while (MorePointsAvailable (svg, pos)) {
                        cp1 = GetPoint (svg, ref pos);
                        if (relative)
                            cp1 = MakeRelative (cp, cp1);
                        Advance (svg, ref pos);
                        
                        formatter.LineTo (cp1);
                        cp = cp1;
                    }
                    cbz = qbz = false;
                    break;
                case 'a':
                    relative = true;
                    goto case 'A';
                case 'A':
                    while (MorePointsAvailable (svg, pos)) {
                        cp1 = GetPoint (svg, ref pos);
                        // this is a width and height so it's not made relative to cp
                        Advance (svg, ref pos);

                        float angle = GetFloat (svg, ref pos);
                        Advance (svg, ref pos);

                        bool is_large = GetFloat (svg, ref pos) != 0.0f;
                        Advance (svg, ref pos);

                        bool positive_sweep = GetFloat (svg, ref pos) != 0.0f;
                        Advance (svg, ref pos);

                        cp2 = GetPoint (svg, ref pos);
                        if (relative)
                            cp2 = MakeRelative (cp, cp2);
                        Advance (svg, ref pos);
                        
                        formatter.ArcTo (cp1, angle, is_large, positive_sweep, cp2, cp);
                        
                        cp = cp2;
                        Advance (svg, ref pos);
                    }
                    qbz = false;
                    cbz = false;
                    break;
                case 'q':
                    relative = true;
                    goto case 'Q';
                case 'Q':
                    while (MorePointsAvailable (svg, pos)) {
                        cp1 = GetPoint (svg, ref pos);
                        if (relative)
                            cp1 = MakeRelative (cp, cp1);
                        Advance (svg, ref pos);
                        
                        cp2 = GetPoint (svg, ref pos);
                        if (relative)
                            cp2 = MakeRelative (cp, cp2);
                        Advance (svg, ref pos);
                        
                        formatter.QuadCurveTo (cp1, cp2);
                        
                        cp = cp2;
                        Advance (svg, ref pos);
                    }
                    qbz = true;
                    qbzp = cp1;
                    cbz = false;
                    break;
                case 'c':
                    relative = true;
                    goto case 'C';
                case 'C':
                    while (MorePointsAvailable (svg, pos)) {
                        cp1 = GetPoint (svg, ref pos);
                        if (relative)
                            cp1 = MakeRelative (cp, cp1);
                        Advance (svg, ref pos);
                        
                        cp2 = GetPoint (svg, ref pos);
                        if (relative)
                            cp2 = MakeRelative (cp, cp2);
                        Advance (svg, ref pos);
                        
                        cp3 = GetPoint (svg, ref pos);
                        if (relative)
                            cp3 = MakeRelative (cp, cp3);
                        Advance (svg, ref pos);

                        formatter.CurveTo (cp1, cp2, cp3);
                        
                        cp1 = cp3;
                    }
                    cp = cp3;
                    cbz = true;
                    cbzp = cp2;
                    qbz = false;
                    break;
                case 't':
                    relative = true;
                    goto case 'T';
                case 'T':
                    while (MorePointsAvailable (svg, pos)) {
                        cp2 = GetPoint (svg, ref pos);
                        if (relative)
                            cp2 = MakeRelative (cp, cp2);
                        if (qbz) {
                            cp1.X = 2 * cp.X - qbzp.X;
                            cp1.Y = 2 * cp.Y - qbzp.Y;
                        } else {
                            cp1 = cp;
                        }
                        formatter.QuadCurveTo (cp1, cp2);
                        qbz = true;
                        qbzp = cp1;
                        cp = cp2;
                        Advance (svg, ref pos);
                    }
                    cbz = false;
                    break;
                case 's':
                    relative = true;
                    goto case 'S';
                case 'S':
                    while (MorePointsAvailable (svg, pos)) {
                        cp2 = GetPoint (svg, ref pos);
                        if (relative)
                            cp2 = MakeRelative (cp, cp2);
                        Advance (svg, ref pos);

                        cp3 = GetPoint (svg, ref pos);
                        if (relative)
                            cp3 = MakeRelative (cp, cp3);

                        if (cbz) {
                            cp1.X = 2 * cp.X - cbzp.X;
                            cp1.Y = 2 * cp.Y - cbzp.Y;
                        } else {
                            cp1 = cp;
                        }
                        formatter.CurveTo (cp1, cp2, cp3);
                        cbz = true;
                        cbzp = cp2;
                        cp = cp3;
                        Advance (svg, ref pos);
                    }
                    qbz = false;
                    break;
                case 'v':
                    relative = true;
                    goto case 'V';
                case 'V':
                    float y = GetFloat (svg, ref pos);
                    if (relative)
                        y += cp.Y;
                    cp = new PointF (cp.X, y);
                    formatter.LineTo (cp);
                    cbz = qbz = false;
                    break;
                case 'z':
                case 'Z':
                    formatter.ClosePath ();
                    formatter.MoveTo (start);
                    cp = start;
                    cbz = qbz = false;
                    break;
                default:
                    throw new FormatException (c.ToString ());
                }
            }
            formatter.Epilogue ();
        }
    }
}


//相关接口定义:ISourceFormatter.cs

// Authors:
//    Sebastien Pouliot  <sebastien@xamarin.com>
//
// Copyright 2012 Xamarin Inc.
//
// Licensed under the GNU LGPL 2 license only (no "later versions")

using System;
using System.Drawing;

namespace Poupou.SvgPathConverter {
    
    public interface ISourceFormatter {
    
        void Prologue (string name);
        void Epilogue ();
    
        void MoveTo (PointF pt);
        void LineTo (PointF pt);
        void QuadCurveTo (PointF pt1, PointF pt2);
        void CurveTo (PointF pt1, PointF pt2, PointF pt3);
        void ArcTo (PointF size, float angle, bool isLarge, bool sweep, PointF ep, PointF sp);
        void ClosePath ();
    }
}


//辅助类:FormatterRocks.cs

// Authors:
//    Sebastien Pouliot  <sebastien@xamarin.com>
//
// Copyright 2012 Xamarin Inc.
//
// This file is mostly based on the C++ code from once magnificent Moonlight
// https://github.com/mono/moon/blob/master/src/moon-path.cpp
// Copyright 2007-2008 Novell, Inc. (http://www.novell.com)
//
// Licensed under the GNU LGPL 2 license only (no "later versions")

using System;
using System.Drawing;
using System.IO;

namespace Poupou.SvgPathConverter {
    
    public static class FormatterRocks {

        static bool IsNearZero (float value)
        {
            return Math.Abs (value) < 0.000019;
        }

        // The SVG Arc is a bit more complex than others - and also quite different than many existing API
        // This implementation will use a ISourceFormatter's CurveTo method to draw the arc
        public static void ArcHelper (this ISourceFormatter formatter, PointF size, float anglef,
            bool isLarge, bool sweep, PointF endPoint, PointF startPoint)
        {
            if (IsNearZero (endPoint.X - startPoint.X) && IsNearZero (endPoint.Y - startPoint.Y))
                return;

            // Correction of out-of-range radii, see F6.6 (step 1)
            if (IsNearZero (size.X) || IsNearZero (size.Y)) {
                // treat this as a straight line (to end point)
                formatter.LineTo (endPoint);
                return;
            }

            // Correction of out-of-range radii, see F6.6.1 (step 2)
            float rx = Math.Abs (size.X);
            float ry = Math.Abs (size.Y);
            
            // convert angle into radians
            double angle = anglef * Math.PI / 180.0f;
            
            // variables required for F6.3.1
            double cos_phi = Math.Cos (angle);
            double sin_phi = Math.Sin (angle);
            double dx2 = (startPoint.X - endPoint.X) / 2.0;
            double dy2 = (startPoint.Y - endPoint.Y) / 2.0;
            double x1p = cos_phi * dx2 + sin_phi * dy2;
            double y1p = cos_phi * dy2 - sin_phi * dx2;
            double x1p2 = x1p * x1p;
            double y1p2 = y1p * y1p;
            float rx2 = rx * rx;
            float ry2 = ry * ry;
            
            // Correction of out-of-range radii, see F6.6.2 (step 4)
            double lambda = (x1p2 / rx2) + (y1p2 / ry2);
            if (lambda > 1.0) {
                // see F6.6.3
                float lambda_root = (float) Math.Sqrt (lambda);
                rx *= lambda_root;
                ry *= lambda_root;
                // update rx2 and ry2
                rx2 = rx * rx;
                ry2 = ry * ry;
            }
            
            double cxp, cyp, cx, cy;
            double c = (rx2 * ry2) - (rx2 * y1p2) - (ry2 * x1p2);
            
            // check if there is no possible solution (i.e. we can't do a square root of a negative value)
            if (c < 0.0) {
                // scale uniformly until we have a single solution (see F6.2) i.e. when c == 0.0
                float scale = (float) Math.Sqrt (1.0 - c / (rx2 * ry2));
                rx *= scale;
                ry *= scale;
                // update rx2 and ry2
                rx2 = rx * rx;
                ry2 = ry * ry;
                
                // step 2 (F6.5.2) - simplified since c == 0.0
                cxp = 0.0;
                cyp = 0.0;
                
                // step 3 (F6.5.3 first part) - simplified since cxp and cyp == 0.0
                cx = 0.0;
                cy = 0.0;
            } else {
                // complete c calculation
                c = Math.Sqrt (c / ((rx2 * y1p2) + (ry2 * x1p2)));
                
                // inverse sign if Fa == Fs
                if (isLarge == sweep)
                    c = -c;
                
                // step 2 (F6.5.2)
                cxp = c * ( rx * y1p / ry);
                cyp = c * (-ry * x1p / rx);
                
                // step 3 (F6.5.3 first part)
                cx = cos_phi * cxp - sin_phi * cyp;
                cy = sin_phi * cxp + cos_phi * cyp;
            }
            
            // step 3 (F6.5.3 second part) we now have the center point of the ellipse
            cx += (startPoint.X + endPoint.X) / 2.0;
            cy += (startPoint.Y + endPoint.Y) / 2.0;
            
            // step 4 (F6.5.4)
            // we dont' use arccos (as per w3c doc), see http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
            // note: atan2 (0.0, 1.0) == 0.0
            double at = Math.Atan2 (((y1p - cyp) / ry), ((x1p - cxp) / rx));
            double theta1 = (at < 0.0) ? 2.0 * Math.PI + at : at;
            
            double nat = Math.Atan2 (((-y1p - cyp) / ry), ((-x1p - cxp) / rx));
            double delta_theta = (nat < at) ? 2.0 * Math.PI - at + nat : nat - at;
            
            if (sweep) {
                // ensure delta theta < 0 or else add 360 degrees
                if (delta_theta < 0.0)
                    delta_theta += 2.0 * Math.PI;
            } else {
                // ensure delta theta > 0 or else substract 360 degrees
                if (delta_theta > 0.0)
                    delta_theta -= 2.0 * Math.PI;
            }
            
            // add several cubic bezier to approximate the arc (smaller than 90 degrees)
            // we add one extra segment because we want something smaller than 90deg (i.e. not 90 itself)
            int segments = (int) (Math.Abs (delta_theta / Math.PI)) + 1;
            double delta = delta_theta / segments;
            
            // http://www.stillhq.com/ctpfaq/2001/comp.text.pdf-faq-2001-04.txt (section 2.13)
            float bcp = (float) (4.0 / 3 * (1 - Math.Cos (delta / 2)) / Math.Sin (delta / 2));
            
            double cos_phi_rx = cos_phi * rx;
            double cos_phi_ry = cos_phi * ry;
            double sin_phi_rx = sin_phi * rx;
            double sin_phi_ry = sin_phi * ry;
            
            double cos_theta1 = Math.Cos (theta1);
            double sin_theta1 = Math.Sin (theta1);

            PointF c1, c2;
            
            int i;
            for (i = 0; i < segments; ++i) {
                // end angle (for this segment) = current + delta
                double theta2 = theta1 + delta;
                double cos_theta2 = Math.Cos (theta2);
                double sin_theta2 = Math.Sin (theta2);
                
                // first control point (based on start point sx,sy)
                c1.X = startPoint.X - bcp * (float) (cos_phi_rx * sin_theta1 + sin_phi_ry * cos_theta1);
                c1.Y = startPoint.Y + bcp * (float) (cos_phi_ry * cos_theta1 - sin_phi_rx * sin_theta1);
                
                // end point (for this segment)
                endPoint.X = (float) (cx + (cos_phi_rx * cos_theta2 - sin_phi_ry * sin_theta2));
                endPoint.Y = (float) (cy + (sin_phi_rx * cos_theta2 + cos_phi_ry * sin_theta2));
                
                // second control point (based on end point ex,ey)
                c2.X = endPoint.X + bcp * (float) (cos_phi_rx * sin_theta2 + sin_phi_ry * cos_theta2);
                c2.Y = endPoint.Y + bcp * (float) (sin_phi_rx * sin_theta2 - cos_phi_ry * cos_theta2);
                
                formatter.CurveTo (c1, c2, endPoint);
                
                // next start point is the current end point (same for angle)
                startPoint = endPoint;
                theta1 = theta2;
                // avoid recomputations
                cos_theta1 = cos_theta2;
                sin_theta1 = sin_theta2;
            }
        }
    }
}


// 从接口派生的CSharpCoreGraphicsFormatter.cs

// Authors:
//    Sebastien Pouliot  <sebastien@xamarin.com>
//
// Copyright 2012-2013 Xamarin Inc.
//
// Licensed under the GNU LGPL 2 license only (no "later versions")

using System;
using System.Drawing;
using System.Globalization;
using System.IO;

namespace Poupou.SvgPathConverter {

    public class CSharpCoreGraphicsFormatter : ISourceFormatter {

        TextWriter writer;

        public CSharpCoreGraphicsFormatter (TextWriter textWriter)
        {
            writer = textWriter;
        }
        
        public void Prologue (string name)
        {
            writer.WriteLine ("\tstatic void {0} (CGContext c)", name);
            writer.WriteLine ("\t{");
        }
    
        public void Epilogue ()
        {
            writer.WriteLine ("\t\tc.FillPath ();");
            writer.WriteLine ("\t\tc.StrokePath ();");
            writer.WriteLine ("\t}");
            writer.WriteLine ();
        }
    
        public void MoveTo (PointF pt)
        {
            writer.WriteLine ("\t\tc.MoveTo ({0}f, {1}f);", pt.X.ToString (CultureInfo.InvariantCulture),
                pt.Y.ToString (CultureInfo.InvariantCulture));
        }
    
        public void LineTo (PointF pt)
        {
            writer.WriteLine ("\t\tc.AddLineToPoint ({0}f, {1}f);", pt.X.ToString (CultureInfo.InvariantCulture),
                 pt.Y.ToString (CultureInfo.InvariantCulture));
        }
    
        public void ClosePath ()
        {
            writer.WriteLine ("\t\tc.ClosePath ();");
        }
    
        public void QuadCurveTo (PointF pt1, PointF pt2)
        {
            writer.WriteLine ("\t\tc.AddQuadCurveToPoint ({0}f, {1}f, {2}f, {3}f);",
                pt1.X.ToString (CultureInfo.InvariantCulture), pt1.Y.ToString (CultureInfo.InvariantCulture),
                pt2.X.ToString (CultureInfo.InvariantCulture), pt2.Y.ToString (CultureInfo.InvariantCulture));
        }

        public void CurveTo (PointF pt1, PointF pt2, PointF pt3)
        {
            writer.WriteLine ("\t\tc.AddCurveToPoint ({0}f, {1}f, {2}f, {3}f, {4}f, {5}f);",
                pt1.X.ToString (CultureInfo.InvariantCulture), pt1.Y.ToString (CultureInfo.InvariantCulture),
                pt2.X.ToString (CultureInfo.InvariantCulture), pt2.Y.ToString (CultureInfo.InvariantCulture),
                pt3.X.ToString (CultureInfo.InvariantCulture), pt3.Y.ToString (CultureInfo.InvariantCulture));
        }

        public void ArcTo (PointF size, float angle, bool isLarge, bool sweep, PointF endPoint, PointF startPoint)
        {
            this.ArcHelper (size, angle, isLarge, sweep, endPoint, startPoint);
        }
    }
}


目录
相关文章
|
11月前
|
XML 前端开发 C#
C#编程实践:解析HTML文档并执行元素匹配
通过上述步骤,可以在C#中有效地解析HTML文档并执行元素匹配。HtmlAgilityPack提供了一个强大而灵活的工具集,可以处理各种HTML解析任务。
433 19
|
存储 算法 安全
如何控制上网行为——基于 C# 实现布隆过滤器算法的上网行为管控策略研究与实践解析
在数字化办公生态系统中,企业对员工网络行为的精细化管理已成为保障网络安全、提升组织效能的核心命题。如何在有效防范恶意网站访问、数据泄露风险的同时,避免过度管控对正常业务运作的负面影响,构成了企业网络安全领域的重要研究方向。在此背景下,数据结构与算法作为底层技术支撑,其重要性愈发凸显。本文将以布隆过滤器算法为研究对象,基于 C# 编程语言开展理论分析与工程实践,系统探讨该算法在企业上网行为管理中的应用范式。
369 8
|
存储 监控 算法
解析公司屏幕监控软件中 C# 字典算法的数据管理效能与优化策略
数字化办公的时代背景下,企业为维护信息安全并提升管理效能,公司屏幕监控软件的应用日益普及。此软件犹如企业网络的 “数字卫士”,持续记录员工电脑屏幕的操作动态。然而,伴随数据量的持续增长,如何高效管理这些监控数据成为关键议题。C# 中的字典(Dictionary)数据结构,以其独特的键值对存储模式和高效的操作性能,为公司屏幕监控软件的数据管理提供了有力支持。下文将深入探究其原理与应用。
408 4
|
机器学习/深度学习 监控 算法
员工上网行为监控软件中基于滑动窗口的C#流量统计算法解析​
在数字化办公环境中,员工上网行为监控软件需要高效处理海量网络请求数据,同时实时识别异常行为(如高频访问非工作网站)。传统的时间序列统计方法因计算复杂度过高,难以满足低延迟需求。本文将介绍一种基于滑动窗口的C#统计算法,通过动态时间窗口管理,实现高效的行为模式分析与流量计数。
415 2
|
监控 算法 安全
基于 C# 的内网行为管理软件入侵检测算法解析
当下数字化办公环境中,内网行为管理软件已成为企业维护网络安全、提高办公效率的关键工具。它宛如一位恪尽职守的网络守护者,持续监控内网中的各类活动,以确保数据安全及网络稳定。在其诸多功能实现的背后,先进的数据结构与算法发挥着至关重要的作用。本文将深入探究一种应用于内网行为管理软件的 C# 算法 —— 基于二叉搜索树的入侵检测算法,并借助具体代码例程予以解析。
257 4
|
数据采集 机器学习/深度学习 人工智能
静态长效代理IP利用率瓶颈解析与优化路径
在信息化时代,互联网已深度融入社会各领域,HTTP动态代理IP应用广泛,但静态长效代理IP利用率未达百分百,反映出行业结构性矛盾。优质IP资源稀缺且成本高,全球IPv4地址分配殆尽,高质量IP仅占23%。同时,代理服务管理存在技术瓶颈,如IP池更新慢、质量监控缺失及多协议支持不足。智能调度系统也面临风险预判弱、负载均衡失效等问题。未来需构建分布式IP网络、引入AI智能调度并建立质量认证体系,以提升资源利用率,推动数字经济发展。
391 2
|
存储 监控 算法
企业内网监控系统中基于哈希表的 C# 算法解析
在企业内网监控系统中,哈希表作为一种高效的数据结构,能够快速处理大量网络连接和用户操作记录,确保网络安全与效率。通过C#代码示例展示了如何使用哈希表存储和管理用户的登录时间、访问IP及操作行为等信息,实现快速的查找、插入和删除操作。哈希表的应用显著提升了系统的实时性和准确性,尽管存在哈希冲突等问题,但通过合理设计哈希函数和冲突解决策略,可以确保系统稳定运行,为企业提供有力的安全保障。
|
开发框架 C# Android开发
C#一分钟浅谈:Xamarin 移动应用开发
随着移动设备的普及,Xamarin 成为跨平台移动应用开发的重要工具,允许开发者使用 C# 编写一次代码,即可在 iOS、Android 和 Windows Phone 上运行。本文介绍 Xamarin 的基本概念、开发环境搭建、常见问题及解决方案,并通过代码示例详细讲解。
478 0
|
C# 开发者
C# 10.0 新特性解析
C# 10.0 在性能、可读性和开发效率方面进行了多项增强。本文介绍了文件范围的命名空间、记录结构体、只读结构体、局部函数的递归优化、改进的模式匹配和 lambda 表达式等新特性,并通过代码示例帮助理解这些特性。
379 2
|
编译器 C# 开发者
C# 9.0 新特性解析
C# 9.0 是微软在2020年11月随.NET 5.0发布的重大更新,带来了一系列新特性和改进,如记录类型、初始化器增强、顶级语句、模式匹配增强、目标类型的新表达式、属性模式和空值处理操作符等,旨在提升开发效率和代码可读性。本文将详细介绍这些新特性,并提供代码示例和常见问题解答。
483 7
C# 9.0 新特性解析

推荐镜像

更多