这三种清除文本框的方法有什么区别?

时间:2013-08-29 12:11:29

标签: c# wpf textbox

我对以下三种清除文本框内容的方法感到有点困惑。我正在使用WPF并发现All正在工作,但我无法找到差异。

有人可以通过一些例子向我解释一下吗?

  • txtUserName.Clear();
  • txtUserName.Text = string.Empty;
  • txtUserName.Text = "";

10 个答案:

答案 0 :(得分:25)

如果不是真的很深:

清除:从TextBox中删除内容,可能会删除随其分配的资源

    public void Clear()
    {
      using (this.TextSelectionInternal.DeclareChangeBlock())
      {
        this.TextContainer.DeleteContentInternal(this.TextContainer.Start, this.TextContainer.End);
        this.TextSelectionInternal.Select(this.TextContainer.Start, this.TextContainer.Start);
      }
    }

将空字符串(因为string.Empty和“”相等)分配给Text属性只需将空字符串赋值给附加属性TextBox.TextProperty:

public string Text
{
  get
  {
    return (string) this.GetValue(TextBox.TextProperty);
  }
  set
  {
    this.SetValue(TextBox.TextProperty, (object) value);
  }
}

答案 1 :(得分:19)

Clear()方法不只是删除TextBox中的文字。它删除所有内容并重置文本选择和插入符号@ syned的答案很好地显示。

对于txtUserName.Text = "";示例,如果字符串池中不存在string对象并将其设置为Text属性,则框架将创建一个空""对象。但是,如果已在应用程序中使用了字符串txtUserName.Text = string.Empty;,则Framework将使用池中的此值。

对于string示例,框架不会创建空Text对象,而是引用空字符串常量,并将其设置为Clear()属性。

在性能测试中,已经显示(在In C#, should I use string.Empty or String.Empty or “”?帖子中)后两个例子之间确实没有任何有用的区别。调用{{1}}方法肯定是最慢的,但这显然是因为它还有其他工作要做以及清除文本。即便如此,三个选项之间的性能差异仍然几乎无法察觉。

答案 2 :(得分:4)

如果你落后于某些性能差异或内存泄漏,那么(在设置文本而不是使用.Clear()时只需要对事件进行一些额外的调用)

但是,在使用MVVM 时无法控制自身,因此只有通过将文本设置为带有TextBox的binded属性才能清除文本。

在标准应用程序中,你可以做任何你想做的事情(我更喜欢使用专为此目的而设计的.Clear()方法。)

答案 3 :(得分:3)

它似乎正在做一些额外的事情,比如检查更改的起源,绑定,更新插入位置以及更新/清除撤消。分配空字符串时可能不需要大部分内容。

/// <summary>
/// Callback for changes to the Text property
/// </summary>
private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    TextBox textBox = (TextBox)d;
    bool inReentrantChange = false;
    int savedCaretIndex = 0;

    if (textBox._isInsideTextContentChange)
    {
        // Ignore property changes that originate from OnTextContainerChanged,
        // unless they contain a different value (indicating that a
        // re-entrant call changed the value)
        if (textBox._newTextValue != DependencyProperty.UnsetValue)
        {
            // OnTextContainerChanged calls
            //      SetCurrentDeferredValue(TextProperty, deferredTextReference)
            // Usually the DeferredTextReference will appear in the new entry
            if (textBox._newTextValue is DeferredTextReference)
            {
                if (e.NewEntry.IsDeferredReference &&
                    e.NewEntry.IsCoercedWithCurrentValue &&
                    e.NewEntry.ModifiedValue.CoercedValue == textBox._newTextValue)
                {
                    return;
                }
            }
            // but if the Text property is data-bound, the deferred reference
            // gets converted to a real string;  during the conversion (in
            // DeferredTextReference.GetValue), the TextBox updates _newTextValue
            // to be the string.
            else if (e.NewEntry.IsExpression)
            {
                object newValue = e.NewEntry.IsCoercedWithCurrentValue
                                    ? e.NewEntry.ModifiedValue.CoercedValue
                                    : e.NewEntry.ModifiedValue.ExpressionValue;
                if (newValue == textBox._newTextValue)
                {
                    return;
                }
            }
        }

        // If we get this far, we're being called re-entrantly with a value
        // different from the one set by OnTextContainerChanged.  We should
        // honor this new value.
        inReentrantChange = true;
        savedCaretIndex = textBox.CaretIndex;
    }

    // CoerceText will have already converted null -> String.Empty,
    // but our default CoerceValueCallback could be overridden by a
    // derived class.  So check again here.
    string newText = (string)e.NewValue;
    if (newText == null)
    {
        newText = String.Empty;
    }

    textBox._isInsideTextContentChange = true;
    try
    {
        using (textBox.TextSelectionInternal.DeclareChangeBlock())
        {
            // Update the text content with new TextProperty value.
            textBox.TextContainer.DeleteContentInternal((TextPointer)textBox.TextContainer.Start, (TextPointer)textBox.TextContainer.End);
            textBox.TextContainer.End.InsertTextInRun(newText);

            // Collapse selection to the beginning of a text box
            textBox.Select(savedCaretIndex, 0);
        }
    }
    finally
    {
        //
        if (!inReentrantChange)
        {
            textBox._isInsideTextContentChange = false;
        }
    }

    // We need to clear undo stack in case when the value comes from
    // databinding or some other expression.
    if (textBox.HasExpression(textBox.LookupEntry(TextBox.TextProperty.GlobalIndex), TextBox.TextProperty))
    {
        UndoManager undoManager = textBox.TextEditor._GetUndoManager();
        if (undoManager != null)
        {
            if (undoManager.IsEnabled)
                undoManager.Clear();
        }
    }
}

答案 4 :(得分:1)

""创建一个对象,而String.Empty不创建任何对象。因此使用String.Empty更有效。

参考:String.Empty vs ""

关于.Clear()我没有得到更好的答案,那么@ syned的回答。

答案 5 :(得分:1)

txtUserName.Clear();

此代码清除文本框。它会将Textbox值设置为“”

txtUserName.Text = string.Empty;

不创建对象。执行速度比txtUserName.Text = "";

txtUserName.Text = "";

创建对象并影响性能。

答案 6 :(得分:1)

让我们一个接一个地阅读这些命令。

txtUserName.Clear();

Clear()命令为texbox分配一个空字符串,就像下一个示例一样。 Source(在这一点上,syned给出了最好的探索)

txtUserName.Text = string.Empty;

现在string.Empty的实际代码是

static String()
{
    Empty = "";
}

意思是在编译时分配字符串“”。

txtUserName.Text = "";

现在,您只需在编译时将“”字符串直接分配给对象。

小边注释txtUserName.Text = "";txtUserName.Text = string.Empty; Source

答案 7 :(得分:1)

string.Empty 字段是一个空字符串文字。它与空字符串文字常量“”略有不同。有一个微妙的区别 - 但在某些情况下可能很重要。它改变了程序的含义

我们在C#程序中使用 string.Empty和“”。 string.Empty字段在运行时由.NET Framework初始化为“”。

您不能将string.Empty用作切换案例,因为it cannot be determined at compile-time by the C# compiler.

Which explain the differences of string.empty and ""

Clear()方法不只是删除TextBox中的文字。它删除所有内容并重置文本选择

答案 8 :(得分:1)

嗯..第一个警告,这个答案有可能超出大多数开发人员目前的共识,但这里是:)尝试阅读它直到最后。

这两个(甚至包括我在内的另外一个)完全相同:

txtUserName.Text = "";
txtUserName.Text = string.Empty;
txtUserName.Text = null;

即使调试配置中的程序集可能会有点不同,我也是肯定的 在更优化的发布模式下,它们将编译为完全相同的程序集。

如果他们没有出现相同的情况 - 这意味着编译器在最优化的翻译中翻译本案例的代码议程的能力降低,换句话说......在其他语言中,这可能会变得相同装配和学术视野 - 它应该是同一个装配。但不是每一个编纂者都关心大部分的学术观点:)

关于第三个家伙txtUserName.Clear()这是一个不同的案例,我假设你和你一样,这个方法的内部实现实际上只是使用这三个任务中的一个。
(和其他人一样)已经提到它除了从文本中删除字符外还做更多事情) 但是,如果您认为面向对象 - 假设有人想要创建一个特殊的文本框,其中包含更多要清除的内容 - 对他来说,使用'Clear'方法覆盖是非常方便的。如果您使用了clear方法 - 当您从基本文本框更改为新的自定义/特殊texbox时,不要更改代码。

总而言之 - 如果你要使用控件,你应该使用它的方法,这意味着使用'Clear()'方法更适合你想要清除它,特别是如果将来某一天您希望将该文本框替换为您自己的自定义文本框。所以至少在语法上它是更好的选择..
但是,如果你想要的只是从文本属性中删除字符,它会造成性能。

这是一个测试WPF下每个效率的小程序。

<Window x:Class="WpfApplication4.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <TextBox Name="txtbx1" Grid.Row="0"/>
    <TextBox Name="txtbx2" Grid.Row="1"/>
    <TextBox Name="txtbx3" Grid.Row="2"/>
    <TextBox Name="txtbx4" Grid.Row="3"/>
</Grid>

using System;
using System.Windows;

namespace WpfApplication4
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DateTime oldTime, newTime;
            TimeSpan delta;

            var iterations = 100000;

            #region Test performance 1

            oldTime = DateTime.Now;
            for (var i = 0; i < iterations; i++)
                txtbx1.Text = "";
            newTime = DateTime.Now;
            delta = newTime - oldTime;
            txtbx1.Text = delta.Milliseconds.ToString();

            #endregion

            #region Test performance 2

            oldTime = DateTime.Now;
            for (var i = 0; i < iterations; i++)
                txtbx2.Text = string.Empty;
            newTime = DateTime.Now;
            delta = newTime - oldTime;
            txtbx2.Text = delta.Milliseconds.ToString();

            #endregion

            #region Test performance 3

            oldTime = DateTime.Now;
            for (var i = 0; i < iterations; i++)
                txtbx3.Text = null;
            newTime = DateTime.Now;
            delta = newTime - oldTime;
            txtbx3.Text = delta.Milliseconds.ToString();

            #endregion

            #region Test performance 4

            oldTime = DateTime.Now;
            for (var i = 0; i < iterations; i++)
                txtbx4.Clear();
            newTime = DateTime.Now;
            delta = newTime - oldTime;
            txtbx4.Text = delta.Milliseconds.ToString();

            #endregion
        }
    }
}

这些是我得到的结果: 43,40,73,443

它是一致的 - 前两个是相同的+/-一个迷你秒或两个, 第三个总是稍微长一点,最后一个肯定比其他所有人都长。

我认为这就是它的深度:)

答案 9 :(得分:0)

有人说 String.Empty “”快,但 String.EMpty 是初始化为“”的静态成员

当我们致电String.Empty时,IL会致电

mscorlib.dll 

IL_0007:  ldsfld     string [mscorlib]System.String::Empty

“”则不是

IL_001a:  ldstr      ""

从逻辑上讲,“” String.Empty

更有效率更有意义