本文的目的是介绍c#–使用Graphics.MeasureString进行字符串测量的详细情况,特别关注c#字符检查的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解c
本文的目的是介绍c# – 使用Graphics.MeasureString进行字符串测量的详细情况,特别关注c#字符检查的相关信息。我们将通过专业的研究、有关数据的分析等多种方式,为您呈现一个全面的了解c# – 使用Graphics.MeasureString进行字符串测量的机会,同时也不会遗漏关于android.graphics.PathMeasure的实例源码、c# – Graphics.DrawString砍掉中间词、c# – System.Drawing.Graphics.DrawString – “参数无效”异常、C# 字符串拼接性能探索 c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能的知识。
本文目录一览:- c# – 使用Graphics.MeasureString进行字符串测量(c#字符检查)
- android.graphics.PathMeasure的实例源码
- c# – Graphics.DrawString砍掉中间词
- c# – System.Drawing.Graphics.DrawString – “参数无效”异常
- C# 字符串拼接性能探索 c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能
c# – 使用Graphics.MeasureString进行字符串测量(c#字符检查)
Graphics grfx = Graphics.FromImage(new Bitmap(1,1)); System.Drawing.Font f = new System.Drawing.Font("Times New Roman",10,FontStyle.Regular); const string text1 = "check_space"; Sizef bounds1 = grfx.MeasureString(text1,f); const string text2 = "check_space "; Sizef bounds2 = grfx.MeasureString(text2,f); Assert.IsTrue(bounds1.Width < bounds2.Width); // I have Fail here!
我想知道为什么我的测试失败了.为什么带尾部空格的文本宽度不比没有空格的文本宽?
更新:我可以理解这两个字符串不相等.但是,我在心理上理解带空格的字符串应该比没有空格的字符串宽.别?
解决方法
Graphics grfx = Graphics.FromImage(new Bitmap(1,FontStyle.Regular); string text1 = "check_space"; Sizef bounds1 = grfx.MeasureString(text1,f,new PointF(0,0),new StringFormat( StringFormatFlags.MeasureTrailingSpaces )); string text2 = "check_space "; Sizef bounds2 = grfx.MeasureString(text2,new StringFormat( StringFormatFlags.MeasureTrailingSpaces ) );
android.graphics.PathMeasure的实例源码
public PathInterpolatorGingerbread(Path path) { final PathMeasure pathMeasure = new PathMeasure(path,false /* forceClosed */); final float pathLength = pathMeasure.getLength(); final int numPoints = (int) (pathLength / PRECISION) + 1; mX = new float[numPoints]; mY = new float[numPoints]; final float[] position = new float[2]; for (int i = 0; i < numPoints; ++i) { final float distance = (i * pathLength) / (numPoints - 1); pathMeasure.getPosTan(distance,position,null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.translate(x,y); for (int i = 0; i < pathMeasures.size(); i++) { Path path1 = new Path(); PathMeasure pathMeasure = pathMeasures.get(i); MyPath path = paths.get(i); if (!isReverse) { pathMeasure.getSegment(0,pathMeasure.getLength() * animatorValue,path1,true); canvas.drawPath(path1,linePaint); } else { pathMeasure.getSegment(0,pathMeasure.getLength() * (1 - animatorValue),linePaint); } drawCircles(radiusArray.get(i),canvas,path.endPoint,path.endDirection,i); } drawCenterCircle(canvas); // drawCircles(radiusArray.get(0),paths.get(0).endPoint,paths.get(0).endDirection); }
public FreshDownloadView(Context context,AttributeSet attrs,int defStyleAttr) { super(context,attrs,defStyleAttr); circular_edge = getResources().getDimension(R.dimen.edge); bounds = new Rect(); mTempBounds = new RectF(); publicPaint = new Paint(); path1 = new Path(); path2 = new Path(); path3 = new Path(); pathMeasure1 = new PathMeasure(); pathMeasure2 = new PathMeasure(); pathMeasure3 = new PathMeasure(); textBounds = new Rect(); parseAttrs(context.obtainStyledAttributes(attrs,R.styleable.FreshDownloadView)); initPaint(); }
private void initData() { defaultPadding = 2 * radius + dp2px(2); defaultPaddingBottom = 2 * radius + dp2px(15); defaultWidth = (int) (2 * defaultPadding + dp2px(200)); defaultHeight = (int) (defaultPadding + defaultPaddingBottom + dp2px(80)); paint = new Paint[ballCount]; for (int i = 0; i < paint.length; i++) { paint[i] = new Paint(Paint.ANTI_ALIAS_FLAG); paint[i].setColor(ballColor); paint[i].setStyle(Paint.Style.FILL); } path = new Path(); pathMeasure = new PathMeasure(); randomBallColors = new int[ballCount]; randomradius = new float[ballCount]; randomTransRatioX = new float[ballCount]; randomTransRatioY = new float[ballCount]; translateFraction = new float[ballCount]; translateAnim = new ValueAnimator[ballCount]; }
private void initRoomTempPath(float[] data) { mRoomTempPath.reset(); // Path path = new Path(); float pointX; float pointY; // 横向 mRoomTempPath.moveto(Xpoint + xFirstPointOffset,getDataY(data[0],Ylabel)); mRoomTempPath.moveto(Xpoint + xFirstPointOffset,Ylabel)); for (int i = 0; i < Xlabel.length; i++) { float startX = Xpoint + i * Xscale + xFirstPointOffset; // 绘制数据连线 if (i != 0) { pointX = Xpoint + (i - 1) * Xscale + xFirstPointOffset; pointY = getDataY(data[i - 1],Ylabel); mRoomTempPath.lineto(pointX,pointY); } if (i == Xlabel.length - 1) { pointX = startX; pointY = getDataY(data[i],pointY); } } mRoomTempPathMeasure = new PathMeasure(mRoomTempPath,false); }
/** * 获取target temp绘线Path数据 * * @param data target temp绘线Path数据 */ private void initTargetTempPath(float[] data) { mTargetTempPath.reset(); float pointX; float pointY; // 横向 mTargetTempPath.moveto(Xpoint + xFirstPointOffset,Ylabel); mTargetTempPath.lineto(pointX,pointY); } } mTargetTempPathMeasure = new PathMeasure(mTargetTempPath,false); }
public void matchVertsToPath(Path path,float bottomCoord,float extraOffset) { PathMeasure pm = new PathMeasure(path,false); for (int i = 0; i < staticVerts.length / 2; i++) { float yIndexValue = staticVerts[i * 2 + 1]; float xIndexValue = staticVerts[i * 2]; float percentOffsetX = (0.000001f + xIndexValue) / bitmap.getWidth(); float percentOffsetX2 = (0.000001f + xIndexValue) / (bitmap.getWidth() + extraOffset); percentOffsetX2 += pathOffsetPercent; pm.getPosTan(pm.getLength() * (1f - percentOffsetX),coords,null); pm.getPosTan(pm.getLength() * (1f - percentOffsetX2),coords2,null); if (yIndexValue == 0) { setXY(drawingVerts,i,coords[0],coords2[1]); } else { float desiredYCoord = bottomCoord; setXY(drawingVerts,desiredYCoord); } } }
public void matchVertsToPath(Path path,desiredYCoord); } } }
public void matchVertsToPath(Path path,false); int index = 0; for (int i = 0; i < staticVerts.length / 2; i++) { float yIndexValue = staticVerts[i * 2 + 1]; float xIndexValue = staticVerts[i * 2]; float percentOffsetX = (0.000001f + xIndexValue) / bitmap.getWidth(); float percentOffsetX2 = (0.000001f + xIndexValue) / (bitmap.getWidth() + extraOffset); percentOffsetX2 += pathOffsetPercent; pm.getPosTan(pm.getLength() * (1f - percentOffsetX),coords2[1] + verticalOffset); } else { float desiredYCoord = Math.max(coords2[1],coords2[1] + easedFoamCoords[Math.min(easedFoamCoords.length - 1,index)]); setXY(drawingVerts,desiredYCoord + verticalOffset); index += 1; } } }
@Override public PointF getValue(Keyframe<PointF> keyframe,float keyframeProgress) { PathKeyframe pathKeyframe = (PathKeyframe) keyframe; Path path = pathKeyframe.getPath(); if (path == null) { return keyframe.startValue; } if (pathMeasureKeyframe != pathKeyframe) { pathMeasure = new PathMeasure(path,false); pathMeasureKeyframe = pathKeyframe; } pathMeasure.getPosTan(keyframeProgress * pathMeasure.getLength(),pos,null); point.set(pos[0],pos[1]); return point; }
public SunnyType(Context context,ShortWeatherInfo info) { super(context); mPathFront = new Path(); mPathRear = new Path(); sunPath = new Path(); mPaint = new Paint(); pos = new float[2]; tan = new float[2]; mMatrix = new Matrix(); measure = new PathMeasure(); sunMeasure = new PathMeasure(); currentSunPosition = TimeUtils.getTimeDiffPercent(info.getSunrise(),info.getSunset()); currentMoonPosition = TimeUtils.getTimeDiffPercent(info.getMoonrise(),info.getMoonset()); if (currentSunPosition >= 0 && currentSunPosition <= 1) { setColor(colorDay); boat = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.ic_boat_day); } else { setColor(colorNight); boat = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.ic_boat_night); } cloud = BitmapFactory.decodeResource(getContext().getResources(),R.drawable.ic_cloud); }
public RainType(Context context,@RainLevel int rainLevel,@WindLevel int windLevel) { super(context); setColor(0xFF6188DA); this.rainLevel = rainLevel; this.windLevel = windLevel; mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(Color.WHITE); mPaint.setstrokeWidth(5); mPaint.setStyle(Paint.Style.stroke); mRains = new ArrayList<>(); mSNows = new ArrayList<>(); matrix = new Matrix(); bitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.ic_rain_ground); mdstFlash1 = new Path(); flashPathMeasure1 = new PathMeasure(); mdstFlash2 = new Path(); flashPathMeasure2 = new PathMeasure(); mdstFlash3 = new Path(); flashPathMeasure3 = new PathMeasure(); }
/** * 用来给每一个button设置一个中心点 * * @param orbit 一个特定角度的path */ private void setPos(Path orbit) { PathMeasure measure = new PathMeasure(orbit,false); TextLableView tv; for (int i = 0; i < mButtons.size(); i++) { PopupButton pp = mButtons.get(i); tv = kvs.get(pp); float[] coords = new float[]{0f,0f}; int length = (int) ((i) * measure.getLength() / mButtons.size()); measure.getPosTan(length,null); int px = (int) coords[0] - pp.getMeasuredWidth() / 2; int py = (int) coords[1] - pp.getMeasuredHeight() / 2; int tvx = (int) coords[0] - tv.getMeasuredWidth() / 2; tv.x = tvx; tv.y = py - 60; pp.x = px; pp.y = py; } }
public PathInterpolatorDonut(Path path) { final PathMeasure pathMeasure = new PathMeasure(path,null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } }
private void init() { borderPaint = new Paint(); borderPaint.setColor(borderColor); borderPaint.setStyle(Paint.Style.stroke); borderPaint.setstrokeWidth(borderWidth); rectPaint = new Paint(); rectPaint.setColor(rectColor); rectPaint.setStyle(Paint.Style.FILL); linePaint = new Paint(); linePaint.setAntiAlias(true); linePaint.setColor(lineColor); linePaint.setStyle(Paint.Style.stroke); linePaint.setstrokeWidth(linewidth); linePaint.setstrokeJoin(Paint.Join.ROUND); textPaint = new TextPaint(); textPaint.setAntiAlias(true); textPaint.setColor(textColor); textPaint.setTextSize(textSize); fm = textPaint.getFontMetrics(); path = new Path(); pathDst = new Path(); pm = new PathMeasure(); selectedindex = -1; }
private void init(int selectedBgColor,float pointstrokeWidth,int pathColor,float pathWidth) { pointPaint = new Paint(); pointPaint.setAntiAlias(true); pointPaint.setColor(pointColor); pointPaint.setstrokeWidth(pointstrokeWidth); pointPaint.setStyle(Paint.Style.stroke); pathPaint = new Paint(); pathPaint.setAntiAlias(true); pathPaint.setColor(pathColor); pathPaint.setstrokeWidth(pathWidth); pathPaint.setStyle(Paint.Style.stroke); selectedBgPaint = new Paint(); selectedBgPaint.setAntiAlias(true); selectedBgPaint.setColor(selectedBgColor); selectedBgPaint.setstrokeWidth(0); selectedBgPaint.setStyle(Paint.Style.FILL); selectedBgPaint.setAlpha(100); path = new Path(); pathDst = new Path(); pm = new PathMeasure(); rectoval = new RectF(); selectedindex = -1; }
private void init() { mPaint = new Paint(); mPaint.setStyle(Paint.Style.stroke); // 设置为空心 mPaint.setstrokeWidth(15); // 宽度 mPaint.setColor(Color.RED); // 颜色 mPaint.setstrokeCap(Paint.Cap.ROUND); // 设置画笔为园笔 mPaint.setAntiAlias(true); // 抗锯齿 mPath = new Path(); // 路径 RectF rect = new RectF(-100,-100,100,100); // 测定圆弧的范围 mPath.addArc(rect,-90,359.9f); // 设置路径范围,起始角度,终止角度 mPathMeasure = new PathMeasure(mPath,false); // 初始化要截取的路径 valueAnimator = ValueAnimator.ofFloat(0f,1f).setDuration(2500); valueAnimator.setRepeatCount(ValueAnimator.INFINITE); // 设置动画播放模式 valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { animationValue = (float) animation.getAnimatedValue(); invalidate(); } }); valueAnimator.start(); }
public PathInterpolatorBase(Path path) { final PathMeasure pathMeasure = new PathMeasure(path,false /* forceClosed */); final float pathLength = pathMeasure.getLength(); final int numPoints = (int) (pathLength / PRECISION) + 1; mX = new float[numPoints]; mY = new float[numPoints]; final float[] position = new float[2]; for (int i = 0; i < numPoints; ++i) { final float distance = (i * pathLength) / (numPoints - 1); pathMeasure.getPosTan(distance,null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } }
public PathInterpolatorGingerbread(Path path) { final PathMeasure pathMeasure = new PathMeasure(path,null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } }
private Point calculateItemPositions(Integer startAngle,Integer endAngle) { final Point center = getActionViewCenter(); RectF area = new RectF(center.x - radius,center.y - radius,center.x + radius,center.y + radius); Path orbit = new Path(); orbit.addArc(area,startAngle,endAngle - startAngle); PathMeasure measure = new PathMeasure(orbit,false); // Prevent overlapping when it is a full circle int divisor; if (Math.abs(endAngle - startAngle) >= 360 || subMenuButtons.size() <= 1) { divisor = subMenuButtons.size(); } else { divisor = subMenuButtons.size() - 1; } // Measure the path in order to find points that have the same distance between each other for (int i = 0; i < subMenuButtons.size(); i++) { SubButton currentSubButton = subMenuButtons.get(i); float[] coordinates = new float[]{0f,0f}; int factor = animationType == AnimationType.RADIAL ? 0 : i; measure.getPosTan(factor * measure.getLength() / divisor,coordinates,null); currentSubButton.setX((int) coordinates[0] - currentSubButton.getWidth() / 2); currentSubButton.setY((int) coordinates[1] - currentSubButton.getHeight() / 2); } return center; }
public TagViewGroup(Context context,defStyleAttr); Resources.Theme theme = context.getTheme(); TypedArray array = theme.obtainStyledAttributes(attrs,R.styleable.TagViewGroup,defStyleAttr,0); mRadius = array.getDimensionPixelSize(R.styleable.TagViewGroup_radius,DipConvertUtils.dip2px(context,DEFAULT_RADIUS)); mInnerRadius = array.getDimensionPixelSize(R.styleable.TagViewGroup_inner_radius,DEFAULT_INNER_RADIUS)); mtdistance = array.getDimensionPixelSize(R.styleable.TagViewGroup_tilt_distance,DEFAULT_TILT_disTANCE)); mVdistance = array.getDimensionPixelSize(R.styleable.TagViewGroup_v_distance,DEFAULT_V_disTANCE)); mLinesWidth = array.getDimensionPixelSize(R.styleable.TagViewGroup_line_width,DEFAULT_LInes_WIDTH)); mRippleMaxRadius = array.getDimensionPixelSize(R.styleable.TagViewGroup_ripple_maxRadius,DEFAULT_RIPPLE_MAX_RADIUS)); mRippleAlpha = array.getInteger(R.styleable.TagViewGroup_ripple_alpha,DEFULT_RIPPLE_ALPHA); mRippleMinRadius = mInnerRadius + (mRadius - mInnerRadius) / 2; array.recycle(); mPaint = new Paint(); mPath = new Path(); mdstPath = new Path(); mPathMeasure = new PathMeasure(); mPaint.setAntiAlias(true); mGestureDetector = new GestureDetectorCompat(context,new TagOnGestureListener()); mChildUsed = new int[4]; mCenterRect = new RectF(); }
private void initTool() { oPaint = new Paint(Paint.ANTI_ALIAS_FLAG); oPaint.setStyle(Paint.Style.FILL_AND_stroke); cPaint = new Paint(Paint.ANTI_ALIAS_FLAG); cPaint.setStyle(Paint.Style.stroke); cPaint.setstrokeCap(Paint.Cap.ROUND); sPaint = new Paint(Paint.ANTI_ALIAS_FLAG); sPaint.setStyle(Paint.Style.FILL); path = new Path(); dstPath = new Path(); pathMeasure = new PathMeasure(); for (int i = 0; i < menuRectFs.length; i++) { menuRectFs[i] = new RectF(); } }
public PathInterpolatorDonut(Path path) { final PathMeasure pathMeasure = new PathMeasure(path,null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } }
public void matchVertsToPath(Path path,desiredYCoord); } } }
private void reMeasure() { int mViewWidth = getWidth(); int mViewHeight = getHeight(); mCenterX = mViewWidth / 2; mCenterY = mViewHeight / 2; temp = mRadius / 2.0f * factor; Path path = new Path(); path.moveto(mCenterX - temp,mCenterY - temp); path.lineto(mCenterX + temp,mCenterY + temp); pathLeftMeasure = new PathMeasure(path,false); path = new Path(); path.moveto(mCenterX + temp,mCenterY - temp); path.lineto(mCenterX - temp,mCenterY + temp); pathRightMeasure = new PathMeasure(path,false); }
/** * 画折线 * * @param canvas */ public void drawLines(Canvas canvas,Line line) { if (line != null && isShow) { linePaint.setColor(line.getLineColor()); linePaint.setstrokeWidth(LeafUtil.dp2px(mContext,line.getlinewidth())); linePaint.setStyle(Paint.Style.stroke); List<PointValue> values = line.getValues(); Path path = line.getPath(); int size = values.size(); for (int i = 0; i < size; i++) { PointValue point = values.get(i); if (i == 0) path.moveto(point.getoriginX(),point.getoriginY()); else path.lineto(point.getoriginX(),point.getoriginY()); } measure = new PathMeasure(path,false); linePaint.setPathEffect(createPathEffect(measure.getLength(),phase,0.0f)); canvas.drawPath(path,linePaint); } }
/** * 画折线 * * @param canvas */ public void drawLines(Canvas canvas,Line line,Axis axisY,int moveX) { if(line != null && isShow){ linePaint.setColor(line.getLineColor()); linePaint.setstrokeWidth(LeafUtil.dp2px(mContext,line.getlinewidth())); linePaint.setStyle(Paint.Style.stroke); List<PointValue> values = line.getValues(); Path path = line.getPath(); int size = values.size(); for (int i = 0; i < size; i++) { PointValue point = values.get(i); if(i == 0) path.moveto(point.getoriginX() + moveX,point.getoriginY()); else path.lineto(point.getoriginX() + moveX,0.0f)); canvas.save(Canvas.CLIP_SAVE_FLAG); canvas.clipRect(axisY.getStartX(),mWidth,mHeight); canvas.drawPath(path,linePaint); canvas.restore(); } }
public PathInterpolatorDonut(Path path) { final PathMeasure pathMeasure = new PathMeasure(path,null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } }
/** * 初始化 Path */ private void initPath() { mSearchPath = new Path(); mCirclePath = new Path(); mMeasure = new PathMeasure(); RectF oval1 = new RectF(-50,-50,50,50); mSearchPath.addArc(oval1,45,359.9f); // 放大镜的圆框 RectF oval2 = new RectF(-100,100); mCirclePath.addArc(oval2,359.9f); // 搜索的圆圈 float[] pos = new float[2]; mMeasure.setPath(mCirclePath,false); mMeasure.getPosTan(0,null); // 放大镜手柄的末端 mSearchPath.lineto(pos[0],pos[1]); // 放大镜的手柄 }
@Override public PointF getValue(Keyframe<PointF> keyframe,pos[1]); return point; }
public PathInterpolatorDonut(Path path) { final PathMeasure pathMeasure = new PathMeasure(path,null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } }
public PathInterpolatorDonut(Path path) { final PathMeasure pathMeasure = new PathMeasure(path,null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } }
public PathInterpolatorDonut(Path path) { final PathMeasure pathMeasure = new PathMeasure(path,null /* tangent */); mX[i] = position[0]; mY[i] = position[1]; } }
public FreshDownloadView(Context context,R.styleable.FreshDownloadView)); initPaint(); }
private void createSuccesspath(){ if(mSuccesspath != null){ mSuccesspath.reset(); }else{ mSuccesspath = new Path(); } float mLineWith = 2*mDensity; float left = width/2 - mRadius + mRadius/3 + mLineWith; float top = mPadding + mRadius/2 + mLineWith; float right = width/2 + mRadius - mLineWith - mRadius/3; float bottom = (mLineWith + mRadius) * 1.5f + mPadding/2; float xPoint = width/2 - mRadius/6; mSuccesspath = new Path(); mSuccesspath.moveto(left,mPadding+mRadius + mLineWith); mSuccesspath.lineto(xPoint,bottom); mSuccesspath.lineto(right,top); PathMeasure measure = new PathMeasure(mSuccesspath,false); mSuccesspathLength = measure.getLength(); mSuccesspathIntervals = new float[]{mSuccesspathLength,mSuccesspathLength}; }
private void createFailedPath(){ if(mFailedPath != null){ mFailedPath.reset(); mFailedPath2.reset(); }else{ mFailedPath = new Path(); mFailedPath2 = new Path(); } float left = width/2 - mRadius + mRadius/2; float top = mRadius/2 + mPadding; mFailedPath.moveto(left,top); mFailedPath.lineto(left+mRadius,top+mRadius); mFailedPath2.moveto(width/2 + mRadius/2,top); mFailedPath2.lineto(width/2 - mRadius + mRadius/2,top+mRadius); PathMeasure measure = new PathMeasure(mFailedPath,false); mFailedPathLength = measure.getLength(); mFailedPathIntervals = new float[]{mFailedPathLength,mFailedPathLength}; PathEffect PathEffect = new DashPathEffect(mFailedPathIntervals,mFailedPathLength); mPathEffectPaint2.setPathEffect(PathEffect); }
private void init(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); width = wm.getDefaultdisplay().getWidth(); height = (int) (wm.getDefaultdisplay().getHeight() * 3 / 2f); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setstrokeWidth(2); mPaint.setColor(Color.BLUE); mPaint.setStyle(Paint.Style.stroke); pathMeasure = new PathMeasure(); builderFollower(fllowerCount,fllowers1); builderFollower(fllowerCount,fllowers2); builderFollower(fllowerCount,fllowers3); }
/** * 绘制外层圆环进度和小圆点 */ private void drawRingProgress(Canvas canvas) { Path path = new Path(); path.addArc(mMiddleProgressRect,mStartAngle,mCurrentAngle); PathMeasure pathMeasure = new PathMeasure(path,false); pathMeasure.getPosTan(pathMeasure.getLength() * 1,tan); matrix.reset(); matrix.postTranslate(pos[0] - bitmap.getWidth() / 2,pos[1] - bitmap.getHeight() / 2); canvas.drawPath(path,marcProgresspaint); //起始角度不为0时候才进行绘制小圆点 if (mCurrentAngle == 0) { return; } canvas.drawBitmap(bitmap,matrix,mBitmapPaint); mBitmapPaint.setColor(Color.WHITE); canvas.drawCircle(pos[0],pos[1],8,mBitmapPaint); }
c# – Graphics.DrawString砍掉中间词
其中一个特性是它确定了文本可能的最大字体大小,同时将文本保留在盒子的限制范围内.
这在大多数情况下都可以正常工作,但有时它会将一个单词切成两半以适应它.
所以它可能会显示为……
stackov erflow
而不是
stackoverflow
(但是字体较小)
我认为会有一个StringFormatFlag允许我指定如何完成自动换行.
我想要自动换行,但不是’字符’换行.
谢谢
丰富.
解决方法
TextRenderer.DrawText(e.Graphics,"stackoverflow",this.Font,new Rectangle(10,10,32,32),Color.Black,Color.Empty,textformatFlags.WordBreak | textformatFlags.VerticalCenter | textformatFlags.HorizontalCenter); TextRenderer.DrawText(e.Graphics,"stack overflow",new Rectangle(50,textformatFlags.WordBreak | textformatFlags.VerticalCenter | textformatFlags.HorizontalCenter);
c# – System.Drawing.Graphics.DrawString – “参数无效”异常
注意,最好我可以指出的字体是正确构造的(我只是使用10pt的Arial),rect的大小是正的和有效的,画笔是一个白色的SolidBrush,格式标志不影响输出; ie如果我从调用中排除格式标志,我仍然收到错误.
DrawString调用就在底部附近.
public ActionResult RenderText( string fontFamily,float pointSize,string foreColor,string backColor,bool isBold,bool isItalic,bool isvertical,string align,string[] allText,int textIndex) { // method renders a horizontal or vertical text image,taking all the text strings that will be rendered in each image // and sizing the final bitmap according to which text would take the most space,thereby making it possible to render // a selection of text images all at the same size. Response.ContentType = "image/png"; var fmt = StringFormat.GenericTypographic; if(isvertical) fmt.FormatFlags = StringFormatFlags.DirectionVertical; Func<string,Stringalignment> getAlign = (s => { switch(s.ToLower()) { case "right": return Stringalignment.Far; case "center": return Stringalignment.Center; default: return Stringalignment.Near; } }); fmt.LineAlignment = isvertical ? Stringalignment.Center : getAlign(align); fmt.Alignment = isvertical ? getAlign(align) : Stringalignment.Center; var strings = (allText ?? new string[0]).Where(t => t.Length > 0).ToList(); if(strings.Count == 0) strings.Add("[Missing Text]"); FontStyle style = FontStyle.Regular; if(isBold) if(isItalic) style = FontStyle.Bold | FontStyle.Italic; else style = FontStyle.Bold; else if(isItalic) style = FontStyle.Italic; Font font = new Font(fontFamily,pointSize,style,GraphicsUnit.Point); Color fc = foreColor.IsHexColorString() ? foreColor.ToColorFromHex() : foreColor.ToColor(); Color bc = backColor.IsHexColorString() ? backColor.ToColorFromHex() : backColor.ToColor(); var maxSize = new Size(0,0); using(var tmp = new Bitmap(100,200)) using(var gfx = Graphics.FromImage(tmp)) foreach(var txt in strings) { var size = gfx.MeasureString(txt,font,1000,fmt); maxSize = new Size( Math.Max(Convert.ToInt32(isvertical ? size.Height : size.Width),maxSize.Width),Math.Max(Convert.ToInt32(isvertical ? size.Width : size.Height),maxSize.Width) ); } using(var bmp = new Bitmap(maxSize.Width,maxSize.Height)) { using(var gfx = Graphics.FromImage(bmp)) { gfx.CompositingMode = CompositingMode.sourcecopy; gfx.CompositingQuality = CompositingQuality.HighQuality; gfx.SmoothingMode = SmoothingMode.HighQuality; gfx.InterpolationMode = InterpolationMode.HighQualityBicubic; var rect = new RectangleF(new PointF(0,0),maxSize); gfx.FillRectangle(new SolidBrush(bc),rect); gfx.DrawString(strings[textIndex],new SolidBrush(fc),rect,fmt); } bmp.Save(Response.OutputStream,ImageFormat.Png); } return new EmptyResult(); }
解决方法
gfx.CompositingMode = CompositingMode.sourcecopy;
C# 字符串拼接性能探索 c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能
本文通过ANTS Memory Profiler工具探索c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能。
本文涉及程序为.NET Core 2.0控制台应用程序。
一、常量字符串拼接


private static void TestPerformance(Action action, int times)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for(int i = 0; i < times; i++)
{
action();
}
sw.Stop();
Console.WriteLine(action.Method.Name + ", FullTime: " + sw.ElapsedMilliseconds);
}

1.+方法
1.1连续拼接

private static void AddTest()
{
string s = string.Empty;
s = "1" + "2" + "3" + "4" + "5" + "6" + "7" + "8";
}
运行时间:
内存情况:
IL代码:

.method private hidebysig static void AddTest() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: pop
IL_0006: ret
} // end of method Program::AddTest

1.2分段拼接


private static void AddWithParamTest2()
{
string s = string.Empty;
s += "1";
s += "2";
s += "3";
s += "4";
s += "5";
s += "6";
s += "7";
s += "8";
}

运行时间:
内存情况:
IL代码:

.method private hidebysig static void AddWithParamTest2() cil managed
{
// Code size 87 (0x57)
.maxstack 2
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: ldstr "1"
IL_000a: call string [System.Runtime]System.String::Concat(string,
string)
IL_000f: ldstr "2"
IL_0014: call string [System.Runtime]System.String::Concat(string,
string)
IL_0019: ldstr "3"
IL_001e: call string [System.Runtime]System.String::Concat(string,
string)
IL_0023: ldstr "4"
IL_0028: call string [System.Runtime]System.String::Concat(string,
string)
IL_002d: ldstr "5"
IL_0032: call string [System.Runtime]System.String::Concat(string,
string)
IL_0037: ldstr "6"
IL_003c: call string [System.Runtime]System.String::Concat(string,
string)
IL_0041: ldstr "7"
IL_0046: call string [System.Runtime]System.String::Concat(string,
string)
IL_004b: ldstr "8"
IL_0050: call string [System.Runtime]System.String::Concat(string,
string)
IL_0055: pop
IL_0056: ret
} // end of method Program::AddWithParamTest2

通过IL代码可以看出,分段的+=代码调用的是Concat方法,并且比连续的+多开辟了许多内存空间。
2.Concat方法
2.1分次Concat


private static void ConcatTest()
{
string s = string.Empty;
s = string.Concat(s, "1");
s = string.Concat(s, "2");
s = string.Concat(s, "3");
s = string.Concat(s, "4");
s = string.Concat(s, "5");
s = string.Concat(s, "6");
s = string.Concat(s, "7");
s = string.Concat(s, "8");
}

IL代码:

.method private hidebysig static void AddWithParamTest2() cil managed
{
// Code size 87 (0x57)
.maxstack 2
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: ldstr "1"
IL_000a: call string [System.Runtime]System.String::Concat(string,
string)
IL_000f: ldstr "2"
IL_0014: call string [System.Runtime]System.String::Concat(string,
string)
IL_0019: ldstr "3"
IL_001e: call string [System.Runtime]System.String::Concat(string,
string)
IL_0023: ldstr "4"
IL_0028: call string [System.Runtime]System.String::Concat(string,
string)
IL_002d: ldstr "5"
IL_0032: call string [System.Runtime]System.String::Concat(string,
string)
IL_0037: ldstr "6"
IL_003c: call string [System.Runtime]System.String::Concat(string,
string)
IL_0041: ldstr "7"
IL_0046: call string [System.Runtime]System.String::Concat(string,
string)
IL_004b: ldstr "8"
IL_0050: call string [System.Runtime]System.String::Concat(string,
string)
IL_0055: pop
IL_0056: ret
} // end of method Program::AddWithParamTest2

可见IL代码与+分段拼接常量字符串相同,性能相似。
2.2Concat一次拼接常量字符串

private static void ConcatTest2()
{
string s = string.Empty;
string.Concat(s, "1", "2", "3", "4", "5", "6", "7", "8");
}
运行时间:
内存情况:
IL代码:

.method private hidebysig static void ConcatTest2() cil managed
{
// Code size 88 (0x58)
.maxstack 4
.locals init (string V_0)
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: stloc.0
IL_0006: ldc.i4.s 9
IL_0008: newarr [System.Runtime]System.String
IL_000d: dup
IL_000e: ldc.i4.0
IL_000f: ldloc.0
IL_0010: stelem.ref
IL_0011: dup
IL_0012: ldc.i4.1
IL_0013: ldstr "1"
IL_0018: stelem.ref
IL_0019: dup
IL_001a: ldc.i4.2
IL_001b: ldstr "2"
IL_0020: stelem.ref
IL_0021: dup
IL_0022: ldc.i4.3
IL_0023: ldstr "3"
IL_0028: stelem.ref
IL_0029: dup
IL_002a: ldc.i4.4
IL_002b: ldstr "4"
IL_0030: stelem.ref
IL_0031: dup
IL_0032: ldc.i4.5
IL_0033: ldstr "5"
IL_0038: stelem.ref
IL_0039: dup
IL_003a: ldc.i4.6
IL_003b: ldstr "6"
IL_0040: stelem.ref
IL_0041: dup
IL_0042: ldc.i4.7
IL_0043: ldstr "7"
IL_0048: stelem.ref
IL_0049: dup
IL_004a: ldc.i4.8
IL_004b: ldstr "8"
IL_0050: stelem.ref
IL_0051: call string [System.Runtime]System.String::Concat(string[])
IL_0056: stloc.0
IL_0057: ret
} // end of method Program::ConcatTest2

通过IL代码可以看出,string.Concat(s, s1, s2, s3)并不调用String.Concat方法,而是直接在堆栈上进行操作。因为需要局部变量来标记,比分次调用Concat方法所占的内存要多一些。
3.Format方法
3.1一次Format

private static void FormatTest()
{
string s = string.Empty;
s = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}", "1", "2", "3", "4", "5", "6", "7", "8");
}
运行时间:
内存情况:
IL代码:

.method private hidebysig static void FormatTest() cil managed
{
// Code size 88 (0x58)
.maxstack 5
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: pop
IL_0006: ldstr "{0}{1}{2}{3}{4}{5}{6}{7}"
IL_000b: ldc.i4.8
IL_000c: newarr [System.Runtime]System.Object
IL_0011: dup
IL_0012: ldc.i4.0
IL_0013: ldstr "1"
IL_0018: stelem.ref
IL_0019: dup
IL_001a: ldc.i4.1
IL_001b: ldstr "2"
IL_0020: stelem.ref
IL_0021: dup
IL_0022: ldc.i4.2
IL_0023: ldstr "3"
IL_0028: stelem.ref
IL_0029: dup
IL_002a: ldc.i4.3
IL_002b: ldstr "4"
IL_0030: stelem.ref
IL_0031: dup
IL_0032: ldc.i4.4
IL_0033: ldstr "5"
IL_0038: stelem.ref
IL_0039: dup
IL_003a: ldc.i4.5
IL_003b: ldstr "6"
IL_0040: stelem.ref
IL_0041: dup
IL_0042: ldc.i4.6
IL_0043: ldstr "7"
IL_0048: stelem.ref
IL_0049: dup
IL_004a: ldc.i4.7
IL_004b: ldstr "8"
IL_0050: stelem.ref
IL_0051: call string [System.Runtime]System.String::Format(string,
object[])
IL_0056: pop
IL_0057: ret
} // end of method Program::FormatTest

StringFormat方法虽然是基于StringBuilder,但由于需要遍历字符串来识别占位符,所以比较慢。
3.2Format分次拼接


private static void FormatTest2()
{
string s = string.Empty;
s = string.Format("{0}{1}", s, "1");
s = string.Format("{0}{1}", s, "2");
s = string.Format("{0}{1}", s, "3");
s = string.Format("{0}{1}", s, "4");
s = string.Format("{0}{1}", s, "5");
s = string.Format("{0}{1}", s, "6");
s = string.Format("{0}{1}", s, "7");
s = string.Format("{0}{1}", s, "8");
}

运行时间:
内存情况:
IL代码:

.method private hidebysig static void FormatTest2() cil managed
{
// Code size 143 (0x8f)
.maxstack 3
.locals init (string V_0)
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: stloc.0
IL_0006: ldstr "{0}{1}"
IL_000b: ldloc.0
IL_000c: ldstr "1"
IL_0011: call string [System.Runtime]System.String::Format(string,
object,
object)
IL_0016: stloc.0
IL_0017: ldstr "{0}{1}"
IL_001c: ldloc.0
IL_001d: ldstr "2"
IL_0022: call string [System.Runtime]System.String::Format(string,
object,
object)
IL_0027: stloc.0
IL_0028: ldstr "{0}{1}"
IL_002d: ldloc.0
IL_002e: ldstr "3"
IL_0033: call string [System.Runtime]System.String::Format(string,
object,
object)
IL_0038: stloc.0
IL_0039: ldstr "{0}{1}"
IL_003e: ldloc.0
IL_003f: ldstr "4"
IL_0044: call string [System.Runtime]System.String::Format(string,
object,
object)
IL_0049: stloc.0
IL_004a: ldstr "{0}{1}"
IL_004f: ldloc.0
IL_0050: ldstr "5"
IL_0055: call string [System.Runtime]System.String::Format(string,
object,
object)
IL_005a: stloc.0
IL_005b: ldstr "{0}{1}"
IL_0060: ldloc.0
IL_0061: ldstr "6"
IL_0066: call string [System.Runtime]System.String::Format(string,
object,
object)
IL_006b: stloc.0
IL_006c: ldstr "{0}{1}"
IL_0071: ldloc.0
IL_0072: ldstr "7"
IL_0077: call string [System.Runtime]System.String::Format(string,
object,
object)
IL_007c: stloc.0
IL_007d: ldstr "{0}{1}"
IL_0082: ldloc.0
IL_0083: ldstr "8"
IL_0088: call string [System.Runtime]System.String::Format(string,
object,
object)
IL_008d: stloc.0
IL_008e: ret
} // end of method Program::FormatTest2

分次使用Format方法拼接字符串,即分次调用Format方法,多次循环遍历字符串,耗时更长。
4.StringBuilder方法


private static void BuilderTest()
{
StringBuilder sb = new StringBuilder();
sb.Append("1");
sb.Append("2");
sb.Append("3");
sb.Append("4");
sb.Append("5");
sb.Append("6");
sb.Append("7");
sb.Append("8");
}

运行时间:
内存情况:
IL代码:

.method private hidebysig static void BuilderTest() cil managed
{
// Code size 101 (0x65)
.maxstack 3
IL_0000: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor()
IL_0005: dup
IL_0006: ldstr "1"
IL_000b: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0010: pop
IL_0011: dup
IL_0012: ldstr "2"
IL_0017: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_001c: pop
IL_001d: dup
IL_001e: ldstr "3"
IL_0023: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0028: pop
IL_0029: dup
IL_002a: ldstr "4"
IL_002f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0034: pop
IL_0035: dup
IL_0036: ldstr "5"
IL_003b: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0040: pop
IL_0041: dup
IL_0042: ldstr "6"
IL_0047: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_004c: pop
IL_004d: dup
IL_004e: ldstr "7"
IL_0053: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0058: pop
IL_0059: ldstr "8"
IL_005e: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0063: pop
IL_0064: ret
} // end of method Program::BuilderTest

在短字符串大量拼接的测试中,可以看出一次使用+进行拼接所耗内存最少,所用时间最短。其余方式所耗内存相差不大,但StringBuilder所耗时间明显较短。
由于Format方法内部存在对字符串的遍历,可以推测,随着字符串的长度变长,Format方法所耗时间将会增加。
二、字符串变量拼接(多次循环拼接)


private static void TestPerformanceWithParam<T>(Action<T> action, T t, int times)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < times; i++)
{
action(t);
}
sw.Stop();
Console.WriteLine(action.Method.Name + ", FullTime: " + sw.ElapsedMilliseconds);
}

1.+方法
1.1连续拼接

private static void AddTest(string t)
{
string s = string.Empty;
s = t + t + t + t + t + t + t + t;
}
运行时间:
内存情况:
IL代码:


.method private hidebysig static void AddTest(string t) cil managed
{
// Code size 51 (0x33)
.maxstack 8
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: pop
IL_0006: ldc.i4.8
IL_0007: newarr [System.Runtime]System.String
IL_000c: dup
IL_000d: ldc.i4.0
IL_000e: ldarg.0
IL_000f: stelem.ref
IL_0010: dup
IL_0011: ldc.i4.1
IL_0012: ldarg.0
IL_0013: stelem.ref
IL_0014: dup
IL_0015: ldc.i4.2
IL_0016: ldarg.0
IL_0017: stelem.ref
IL_0018: dup
IL_0019: ldc.i4.3
IL_001a: ldarg.0
IL_001b: stelem.ref
IL_001c: dup
IL_001d: ldc.i4.4
IL_001e: ldarg.0
IL_001f: stelem.ref
IL_0020: dup
IL_0021: ldc.i4.5
IL_0022: ldarg.0
IL_0023: stelem.ref
IL_0024: dup
IL_0025: ldc.i4.6
IL_0026: ldarg.0
IL_0027: stelem.ref
IL_0028: dup
IL_0029: ldc.i4.7
IL_002a: ldarg.0
IL_002b: stelem.ref
IL_002c: call string [System.Runtime]System.String::Concat(string[])
IL_0031: pop
IL_0032: ret
} // end of method Program::AddTest

从IL代码可见,在使用+连续拼接字符串变量时,内部调用了String.Concat(string[])方法。
1.2分段拼接


private static void AddWithParamTest2(string t)
{
string s = string.Empty;
s += t;
s += t;
s += t;
s += t;
s += t;
s += t;
s += t;
s += t;
}

运行时间:
内存情况:
IL代码:

.method private hidebysig static void AddWithParamTest2(string t) cil managed
{
// Code size 55 (0x37)
.maxstack 8
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: ldarg.0
IL_0006: call string [System.Runtime]System.String::Concat(string,
string)
IL_000b: ldarg.0
IL_000c: call string [System.Runtime]System.String::Concat(string,
string)
IL_0011: ldarg.0
IL_0012: call string [System.Runtime]System.String::Concat(string,
string)
IL_0017: ldarg.0
IL_0018: call string [System.Runtime]System.String::Concat(string,
string)
IL_001d: ldarg.0
IL_001e: call string [System.Runtime]System.String::Concat(string,
string)
IL_0023: ldarg.0
IL_0024: call string [System.Runtime]System.String::Concat(string,
string)
IL_0029: ldarg.0
IL_002a: call string [System.Runtime]System.String::Concat(string,
string)
IL_002f: ldarg.0
IL_0030: call string [System.Runtime]System.String::Concat(string,
string)
IL_0035: pop
IL_0036: ret
} // end of method Program::AddWithParamTest2

2.Concat方法
2.1分次concat
IL代码:

.method private hidebysig static void ConcatTest(string t) cil managed
{
// Code size 55 (0x37)
.maxstack 8
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: ldarg.0
IL_0006: call string [System.Runtime]System.String::Concat(string,
string)
IL_000b: ldarg.0
IL_000c: call string [System.Runtime]System.String::Concat(string,
string)
IL_0011: ldarg.0
IL_0012: call string [System.Runtime]System.String::Concat(string,
string)
IL_0017: ldarg.0
IL_0018: call string [System.Runtime]System.String::Concat(string,
string)
IL_001d: ldarg.0
IL_001e: call string [System.Runtime]System.String::Concat(string,
string)
IL_0023: ldarg.0
IL_0024: call string [System.Runtime]System.String::Concat(string,
string)
IL_0029: ldarg.0
IL_002a: call string [System.Runtime]System.String::Concat(string,
string)
IL_002f: ldarg.0
IL_0030: call string [System.Runtime]System.String::Concat(string,
string)
IL_0035: pop
IL_0036: ret
} // end of method Program::ConcatTest

从IL代码来看,同使用+分段拼接相似。
2.2一次拼接
IL代码:

.method private hidebysig static void ConcatTest2(string t) cil managed
{
// Code size 56 (0x38)
.maxstack 4
.locals init (string V_0)
IL_0000: ldsfld string [System.Runtime]System.String::Empty
IL_0005: stloc.0
IL_0006: ldc.i4.s 9
IL_0008: newarr [System.Runtime]System.String
IL_000d: dup
IL_000e: ldc.i4.0
IL_000f: ldloc.0
IL_0010: stelem.ref
IL_0011: dup
IL_0012: ldc.i4.1
IL_0013: ldarg.0
IL_0014: stelem.ref
IL_0015: dup
IL_0016: ldc.i4.2
IL_0017: ldarg.0
IL_0018: stelem.ref
IL_0019: dup
IL_001a: ldc.i4.3
IL_001b: ldarg.0
IL_001c: stelem.ref
IL_001d: dup
IL_001e: ldc.i4.4
IL_001f: ldarg.0
IL_0020: stelem.ref
IL_0021: dup
IL_0022: ldc.i4.5
IL_0023: ldarg.0
IL_0024: stelem.ref
IL_0025: dup
IL_0026: ldc.i4.6
IL_0027: ldarg.0
IL_0028: stelem.ref
IL_0029: dup
IL_002a: ldc.i4.7
IL_002b: ldarg.0
IL_002c: stelem.ref
IL_002d: dup
IL_002e: ldc.i4.8
IL_002f: ldarg.0
IL_0030: stelem.ref
IL_0031: call string [System.Runtime]System.String::Concat(string[])
IL_0036: stloc.0
IL_0037: ret
} // end of method Program::ConcatTest2

从IL代码可以看出,同使用+一次拼接相似。
3.Format

private static void FormatTest(string t)
{
string s = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}", t, t, t, t, t, t, t, t);
}
运行时间:
内存情况:
IL代码:

.method private hidebysig static void FormatTest(string t) cil managed
{
// Code size 50 (0x32)
.maxstack 8
IL_0000: ldstr "{0}{1}{2}{3}{4}{5}{6}{7}"
IL_0005: ldc.i4.8
IL_0006: newarr [System.Runtime]System.Object
IL_000b: dup
IL_000c: ldc.i4.0
IL_000d: ldarg.0
IL_000e: stelem.ref
IL_000f: dup
IL_0010: ldc.i4.1
IL_0011: ldarg.0
IL_0012: stelem.ref
IL_0013: dup
IL_0014: ldc.i4.2
IL_0015: ldarg.0
IL_0016: stelem.ref
IL_0017: dup
IL_0018: ldc.i4.3
IL_0019: ldarg.0
IL_001a: stelem.ref
IL_001b: dup
IL_001c: ldc.i4.4
IL_001d: ldarg.0
IL_001e: stelem.ref
IL_001f: dup
IL_0020: ldc.i4.5
IL_0021: ldarg.0
IL_0022: stelem.ref
IL_0023: dup
IL_0024: ldc.i4.6
IL_0025: ldarg.0
IL_0026: stelem.ref
IL_0027: dup
IL_0028: ldc.i4.7
IL_0029: ldarg.0
IL_002a: stelem.ref
IL_002b: call string [System.Runtime]System.String::Format(string,
object[])
IL_0030: pop
IL_0031: ret
} // end of method Program::FormatTest

时间的损耗主要来自于String.Format方法。
4.StringBuilder方法


private static void BuilderTest(string t)
{
StringBuilder sb = new StringBuilder();
sb.Append(t);
sb.Append(t);
sb.Append(t);
sb.Append(t);
sb.Append(t);
sb.Append(t);
sb.Append(t);
sb.Append(t);
}

运行时间:
内存情况:
IL代码:

.method private hidebysig static void BuilderTest(string t) cil managed
{
// Code size 69 (0x45)
.maxstack 3
IL_0000: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor()
IL_0005: dup
IL_0006: ldarg.0
IL_0007: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_000c: pop
IL_000d: dup
IL_000e: ldarg.0
IL_000f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0014: pop
IL_0015: dup
IL_0016: ldarg.0
IL_0017: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_001c: pop
IL_001d: dup
IL_001e: ldarg.0
IL_001f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0024: pop
IL_0025: dup
IL_0026: ldarg.0
IL_0027: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_002c: pop
IL_002d: dup
IL_002e: ldarg.0
IL_002f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0034: pop
IL_0035: dup
IL_0036: ldarg.0
IL_0037: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_003c: pop
IL_003d: ldarg.0
IL_003e: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_0043: pop
IL_0044: ret
} // end of method Program::BuilderTest

在短字符串(上面所用字符串为“short”)大量循环拼接(上述结果为每个方法循环执行一千万次)时,四种方法的差距并不明显。
当字符串变长后,可见运行结果差距拉大:
此时StringBuilder仍没有明显的优势。
三、字符串变量拼接(循环拼接至一个字符串)
1.+方法


private static void TestAddVeryLong(string s, int times)
{
Stopwatch sw = new Stopwatch();
sw.Start();
string str = string.Empty;
for(int i = 0; i < times; i++)
{
str += s;
}
sw.Stop();
Console.WriteLine("add very long: " + sw.ElapsedMilliseconds);
}

运行时间:
内存情况:
IL代码:

.method private hidebysig static void TestAddVeryLong(string s,
int32 times) cil managed
{
// Code size 71 (0x47)
.maxstack 2
.locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0,
string V_1,
int32 V_2)
IL_0000: newobj instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()
IL_000c: ldsfld string [System.Runtime]System.String::Empty
IL_0011: stloc.1
IL_0012: ldc.i4.0
IL_0013: stloc.2
IL_0014: br.s IL_0022
IL_0016: ldloc.1
IL_0017: ldarg.0
IL_0018: call string [System.Runtime]System.String::Concat(string,
string)
IL_001d: stloc.1
IL_001e: ldloc.2
IL_001f: ldc.i4.1
IL_0020: add
IL_0021: stloc.2
IL_0022: ldloc.2
IL_0023: ldarg.1
IL_0024: blt.s IL_0016
IL_0026: ldloc.0
IL_0027: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()
IL_002c: ldstr "add very long: "
IL_0031: ldloc.0
IL_0032: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
IL_0037: box [System.Runtime]System.Int64
IL_003c: call string [System.Runtime]System.String::Concat(object,
object)
IL_0041: call void [System.Console]System.Console::WriteLine(string)
IL_0046: ret
} // end of method Program::TestAddVeryLong

2.Concat方法


private static void TestConcatVeryLong(string s, int times)
{
Stopwatch sw = new Stopwatch();
sw.Start();
string str = string.Empty;
for (int i = 0; i < times; i++)
{
str = string.Concat(str, s);
}
sw.Stop();
Console.WriteLine("concat very long: " + sw.ElapsedMilliseconds);
}

IL代码:

.method private hidebysig static void TestConcatVeryLong(string s,
int32 times) cil managed
{
// Code size 71 (0x47)
.maxstack 2
.locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0,
string V_1,
int32 V_2)
IL_0000: newobj instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()
IL_000c: ldsfld string [System.Runtime]System.String::Empty
IL_0011: stloc.1
IL_0012: ldc.i4.0
IL_0013: stloc.2
IL_0014: br.s IL_0022
IL_0016: ldloc.1
IL_0017: ldarg.0
IL_0018: call string [System.Runtime]System.String::Concat(string,
string)
IL_001d: stloc.1
IL_001e: ldloc.2
IL_001f: ldc.i4.1
IL_0020: add
IL_0021: stloc.2
IL_0022: ldloc.2
IL_0023: ldarg.1
IL_0024: blt.s IL_0016
IL_0026: ldloc.0
IL_0027: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()
IL_002c: ldstr "concat very long: "
IL_0031: ldloc.0
IL_0032: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
IL_0037: box [System.Runtime]System.Int64
IL_003c: call string [System.Runtime]System.String::Concat(object,
object)
IL_0041: call void [System.Console]System.Console::WriteLine(string)
IL_0046: ret
} // end of method Program::TestConcatVeryLong

由IL代码可见,和使用+性能相似。
3.Format方法


private static void TestFormatVeryLong(string s, int times)
{
Stopwatch sw = new Stopwatch();
sw.Start();
string str = string.Empty;
for (int i = 0; i < times; i++)
{
str = string.Format("{0}{1}", str, s);
}
sw.Stop();
Console.WriteLine("format very long: " + sw.ElapsedMilliseconds);
}

运行时间:
内存情况:
IL代码:

.method private hidebysig static void TestFormatVeryLong(string s,
int32 times) cil managed
{
// Code size 76 (0x4c)
.maxstack 3
.locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0,
string V_1,
int32 V_2)
IL_0000: newobj instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()
IL_000c: ldsfld string [System.Runtime]System.String::Empty
IL_0011: stloc.1
IL_0012: ldc.i4.0
IL_0013: stloc.2
IL_0014: br.s IL_0027
IL_0016: ldstr "{0}{1}"
IL_001b: ldloc.1
IL_001c: ldarg.0
IL_001d: call string [System.Runtime]System.String::Format(string,
object,
object)
IL_0022: stloc.1
IL_0023: ldloc.2
IL_0024: ldc.i4.1
IL_0025: add
IL_0026: stloc.2
IL_0027: ldloc.2
IL_0028: ldarg.1
IL_0029: blt.s IL_0016
IL_002b: ldloc.0
IL_002c: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()
IL_0031: ldstr "format very long: "
IL_0036: ldloc.0
IL_0037: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
IL_003c: box [System.Runtime]System.Int64
IL_0041: call string [System.Runtime]System.String::Concat(object,
object)
IL_0046: call void [System.Console]System.Console::WriteLine(string)
IL_004b: ret
} // end of method Program::TestFormatVeryLong

4.StringBuilder方法


private static void TestBuilderVeryLong(string s, int times)
{
Stopwatch sw = new Stopwatch();
sw.Start();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < times; i++)
{
sb.Append(s);
}
sw.Stop();
Console.WriteLine("builder very long: " + sw.ElapsedMilliseconds);
}

运行时间:
内存情况:
IL代码:

.method private hidebysig static void TestBuilderVeryLong(string s,
int32 times) cil managed
{
// Code size 71 (0x47)
.maxstack 2
.locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0,
class [System.Runtime]System.Text.StringBuilder V_1,
int32 V_2)
IL_0000: newobj instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()
IL_000c: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor()
IL_0011: stloc.1
IL_0012: ldc.i4.0
IL_0013: stloc.2
IL_0014: br.s IL_0022
IL_0016: ldloc.1
IL_0017: ldarg.0
IL_0018: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)
IL_001d: pop
IL_001e: ldloc.2
IL_001f: ldc.i4.1
IL_0020: add
IL_0021: stloc.2
IL_0022: ldloc.2
IL_0023: ldarg.1
IL_0024: blt.s IL_0016
IL_0026: ldloc.0
IL_0027: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()
IL_002c: ldstr "builder very long: "
IL_0031: ldloc.0
IL_0032: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
IL_0037: box [System.Runtime]System.Int64
IL_003c: call string [System.Runtime]System.String::Concat(object,
object)
IL_0041: call void [System.Console]System.Console::WriteLine(string)
IL_0046: ret
} // end of method Program::TestBuilderVeryLong

这个差距在拼接字符串更多的时候会更加明显。
拼接一千万次时,+方法运行一个多小时仍无法得出结果:
而StringBuilder只需要102ms。
+方法的问题在于由于string的特殊性,每次操作都将新开辟内存空间,随着字符串长度的增加、操作次数的增加等,+方法所耗费的内存会越来越大。
而StringBuilder则可以在原有的内存空间中进行修改和扩张,在进行频繁、长串的操作时极大地提高了效率。
显然,如果是不频繁、短字符串的拼接,使用哪种方式拼接字符串没有明显的性能差别(Format可能稍差一些),但如果是频繁的长串操作,StringBuilder具有绝对的优势。
我们今天的关于c# – 使用Graphics.MeasureString进行字符串测量和c#字符检查的分享已经告一段落,感谢您的关注,如果您想了解更多关于android.graphics.PathMeasure的实例源码、c# – Graphics.DrawString砍掉中间词、c# – System.Drawing.Graphics.DrawString – “参数无效”异常、C# 字符串拼接性能探索 c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能的相关信息,请在本站查询。
本文标签: