72

私は拡張メソッドが本当に好きになり始めています...彼女の誰かが、本当に頭を悩ませた、または単に賢いと思ったものに出くわしたのではないかと思っていました。

私が今日書いた例:

他のユーザーのコメントにより編集されました:

public static IEnumerable<int> To(this int fromNumber, int toNumber) {
    while (fromNumber < toNumber) {
        yield return fromNumber;
        fromNumber++;
    }
}

これにより、for ループを foreach ループとして記述できます。

foreach (int x in 0.To(16)) {
    Console.WriteLine(Math.Pow(2, x).ToString());
}

他の例を見るのが待ちきれません!楽しみ!

4

40 に答える 40

19

これは最近私からいくつかの遊びを得ているものです:

public static IDisposable Tag(this HtmlHelper html, string tagName)
{
    if (html == null)
        throw new ArgumentNullException("html");

    Action<string> a = tag => html.Write(String.Format(tag, tagName));
    a("<{0}>");
    return new Memento(() => a("</{0}>"));
}

次のように使用されます:

using (Html.Tag("ul"))
{
    this.Model.ForEach(item => using(Html.Tag("li")) Html.Write(item));
    using(Html.Tag("li")) Html.Write("new");
}

Mementoは便利なクラスです:

public sealed class Memento : IDisposable
{
    private bool Disposed { get; set; }
    private Action Action { get; set; }

    public Memento(Action action)
    {
        if (action == null)
            throw new ArgumentNullException("action");

        Action = action;
    }

    void IDisposable.Dispose()
    {
        if (Disposed)
            throw new ObjectDisposedException("Memento");

        Disposed = true;
        Action();
    }
}

そして、依存関係を完了するには:

public static void Write(this HtmlHelper html, string content)
{
    if (html == null)
        throw new ArgumentNullException("html");

    html.ViewContext.HttpContext.Response.Write(content);
}
于 2009-06-05T05:33:24.170 に答える
18

完全なソリューションは大きすぎてここに置くことはできませんが、DataTableをCSVに簡単に変換できる一連の拡張メソッドを作成しました。

public static String ToCSV(this DataTable dataTable)
{
    return dataTable.ToCSV(null, COMMA, true);
}  

public static String ToCSV(this DataTable dataTable, String qualifier)
{
    return dataTable.ToCSV(qualifier, COMMA, true);
}

private static String ToCSV(this DataTable dataTable, String qualifier, String delimiter, Boolean includeColumnNames)
{
    if (dataTable == null) return null;

    if (qualifier == delimiter)
    {
        throw new InvalidOperationException(
            "The qualifier and the delimiter are identical. This will cause the CSV to have collisions that might result in data being parsed incorrectly by another program.");
    }

    var sbCSV = new StringBuilder();

    var delimiterToUse = delimiter ?? COMMA;

    if (includeColumnNames) 
        sbCSV.AppendLine(dataTable.Columns.GetHeaderLine(qualifier, delimiterToUse));

    foreach (DataRow row in dataTable.Rows)
    {
        sbCSV.AppendLine(row.ToCSVLine(qualifier, delimiterToUse));
    }

    return sbCSV.Length > 0 ? sbCSV.ToString() : null;
}

private static String ToCSVLine(this DataRow dataRow, String qualifier, String delimiter)
{
    var colCount = dataRow.Table.Columns.Count;
    var rowValues = new String[colCount];

    for (var i = 0; i < colCount; i++)
    {
        rowValues[i] = dataRow[i].Qualify(qualifier);
    }

    return String.Join(delimiter, rowValues);
}

private static String GetHeaderLine(this DataColumnCollection columns, String qualifier, String delimiter)
{
    var colCount = columns.Count;
    var colNames = new String[colCount];

    for (var i = 0; i < colCount; i++)
    {
        colNames[i] = columns[i].ColumnName.Qualify(qualifier);
    }

    return String.Join(delimiter, colNames);
}

private static String Qualify(this Object target, String qualifier)
{
    return qualifier + target + qualifier;
}

一日の終わりに、あなたはそれをこのように呼ぶことができます:

someDataTable.ToCSV(); //Plain old CSV
someDataTable.ToCSV("\""); //Double quote qualifier
someDataTable.ToCSV("\"", "\t"); //Tab delimited
于 2009-06-05T04:00:54.090 に答える
13

私は、INotifyPropertyChangedプロパティ名を文字列として渡す必要があるインターフェイスのファンではありません。コンパイル時に、存在するプロパティのプロパティの変更のみを発生させて処理していることを確認する、厳密に型指定された方法が必要です。私はそれを行うためにこのコードを使用します:

public static class INotifyPropertyChangedExtensions
{
    public static string ToPropertyName<T>(this Expression<Func<T>> @this)
    {
        var @return = string.Empty;
        if (@this != null)
        {
            var memberExpression = @this.Body as MemberExpression;
            if (memberExpression != null)
            {
                @return = memberExpression.Member.Name;
            }
        }
        return @return;
    }
}

実装するクラスには、次のINotifyPropertyChangedヘルパー メソッドを含めます。

protected void NotifySetProperty<T>(ref T field, T value,
    Expression<Func<T>> propertyExpression)
{
    if (field == null ? value != null : !field.Equals(value))
    {
        field = value;
        this.NotifyPropertyChanged(propertyExpression.ToPropertyName());
    }
}

最終的に私はこの種のことを行うことができます:

private string _name;
public string Name
{
    get { return _name; }
    set { this.NotifySetProperty(ref _name, value, () => this.Name); }
}

これは厳密に型指定されており、実際に値を変更するプロパティのイベントのみを発生させます。

于 2010-02-26T06:39:50.323 に答える
12

これは正確には賢いわけではありませんが、コードの後半でnullをチェックする代わりに、デフォルトの項目をインラインで指定できるように----OrDefaultメソッドを変更しました。

    public static T SingleOrDefault<T> ( this IEnumerable<T> source, 
                                    Func<T, bool> action, T theDefault )
    {
        T item = source.SingleOrDefault<T>(action);

        if (item != null)
            return item;

        return theDefault;
    }

その信じられないほどシンプルですが、本当にそれらのヌルチェックをクリーンアップするのに役立ちます。UIがトーナメントシステムやゲームプレーヤースロットなどのXアイテムのリストを期待していて、「空いている席」を表示したい場合に最適です。

使用法:

    return jediList.SingleOrDefault( 
                 j => j.LightsaberColor == "Orange", 
               new Jedi() { LightsaberColor = "Orange", Name = "DarthNobody");
于 2009-06-05T04:01:36.727 に答える
12

私が使用したい2つは、私が作成したInsertWhere <T>とRemoveWhere <T>拡張メソッドです。WPFおよびSilverlightでのObservableCollectionsの操作では、順序付きリストを再作成せずに変更する必要があることがよくあります。これらのメソッドを使用すると、提供されたFuncに従って挿入および削除できるため、.OrderBy()を再度呼び出す必要はありません。

    /// <summary>
    /// Removes all items from the provided <paramref name="list"/> that match the<paramref name="predicate"/> expression.
    /// </summary>
    /// <typeparam name="T">The class type of the list items.</typeparam>
    /// <param name="list">The list to remove items from.</param>
    /// <param name="predicate">The predicate expression to test against.</param>
    public static void RemoveWhere<T>(this IList<T> list, Func<T, bool> predicate)
    {
        T[] copy = new T[] { };
        Array.Resize(ref copy, list.Count);
        list.CopyTo(copy, 0);

        for (int i = copy.Length - 1; i >= 0; i--)
        {
            if (predicate(copy[i]))
            {
                list.RemoveAt(i);
            }
        }
    }

    /// <summary>
    /// Inserts an Item into a list at the first place that the <paramref name="predicate"/> expression fails.  If it is true in all cases, then the item is appended to the end of the list.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="list"></param>
    /// <param name="obj"></param>
    /// <param name="predicate">The sepcified function that determines when the <paramref name="obj"/> should be added. </param>
    public static void InsertWhere<T>(this IList<T> list, T obj, Func<T, bool> predicate)
    {
        for (int i = 0; i < list.Count; i++)
        { 
            // When the function first fails it inserts the obj paramiter. 
            // For example, in a list myList of ordered Int32's {1,2,3,4,5,10,12}
            // Calling myList.InsertWhere( 8, x => 8 > x) inserts 8 once the list item becomes greater then or equal to it.
            if(!predicate(list[i]))
            {
                list.Insert(i, obj);
                return;
            }
        }

        list.Add(obj);
    }

編集:
Talljoeは、私が急いで作成したRemoveWhere/RemoveAllにいくつかの重要な改善を加えました。RemoveWhereの数秒(私はそれを待つのにうんざりしていました)とは対照的に、〜3millアイテムが3つおきに削除されるので、新しいバージョンは〜50ミリ秒(List.RemoveAllを呼び出すことができる場合は10ミリ秒未満!)しかかかりません。

これが彼の大幅に改善されたバージョンです、ありがとう!

    public static void RemoveAll<T>(this IList<T> instance, Predicate<T> predicate)
    {
        if (instance == null)
            throw new ArgumentNullException("instance");
        if (predicate == null)
            throw new ArgumentNullException("predicate");
        if (instance is T[])
            throw new NotSupportedException();

        var list = instance as List<T>;
        if (list != null)
        {
            list.RemoveAll(predicate);
            return;
        }

        int writeIndex = 0;
        for (int readIndex = 0; readIndex < instance.Count; readIndex++)
        {
            var item = instance[readIndex];
            if (predicate(item)) continue;

            if (readIndex != writeIndex)
            {
                instance[writeIndex] = item;
            }
            ++writeIndex;
        }

        if (writeIndex != instance.Count)
        {
            for (int deleteIndex = instance.Count - 1; deleteIndex >= writeIndex; --deleteIndex)
            {
                instance.RemoveAt(deleteIndex);
            }
        }
    }
于 2009-06-05T04:09:39.580 に答える
11

これが私が一緒にハッキングしたものですので、気軽に穴を開けてください。整数の(順序付けられた)リストを受け取り、連続する範囲の文字列のリストを返します。例えば:

1,2,3,7,10,11,12  -->  "1-3","7","10-12"

関数(静的クラス内):

public static IEnumerable<string> IntRanges(this IEnumerable<int> numbers)
{
    int rangeStart = 0;
    int previous = 0;

    if (!numbers.Any())
        yield break;

    rangeStart = previous = numbers.FirstOrDefault();

    foreach (int n in numbers.Skip(1))
    {
        if (n - previous > 1) // sequence break - yield a sequence
        {
            if (previous > rangeStart)
            {
                yield return string.Format("{0}-{1}", rangeStart, previous);
            }
            else
            {
                yield return rangeStart.ToString();
            }
            rangeStart = n;
        }
        previous = n;
    }

    if (previous > rangeStart)
    {
        yield return string.Format("{0}-{1}", rangeStart, previous);
    }
    else
    {
        yield return rangeStart.ToString();
    }
}

使用例:

this.WeekDescription = string.Join(",", from.WeekPattern.WeekPatternToInts().IntRanges().ToArray());

このコードは、DailyWTFに値するタイムテーブルアプリケーションからのデータを変換するために使用されます。WeekPatternは、文字列「0011011100...」に格納されているビットマスクです。WeekPatternToInts()は、これをIEnumerable <int>(この場合は[3,4,6,7,8])に変換し、「3-4,6-8」になります。これは、講義が行われるアカデミックウィーク範囲のコンパクトな説明をユーザーに提供します。

于 2009-06-05T04:06:32.733 に答える
11

.Debugifyオブジェクトをログ ファイルにダンプするのに役立つさまざまな拡張メソッドがあります。たとえば、これが私のDictionary debugifyです(List、Datatable、param配列などにこれらがあります):

public static string Debugify<TKey, TValue>(this Dictionary<TKey, TValue> dictionary) {
    string Result = "";

    if (dictionary.Count > 0) {
        StringBuilder ResultBuilder = new StringBuilder();

        int Counter = 0;
        foreach (KeyValuePair<TKey, TValue> Entry in dictionary) {
            Counter++;
            ResultBuilder.AppendFormat("{0}: {1}, ", Entry.Key, Entry.Value);
            if (Counter % 10 == 0) ResultBuilder.AppendLine();
        }
        Result = ResultBuilder.ToString();
    }
    return Result;
}

そして、これは DbParameterCollection の 1 つです (データベース呼び出しをログ ファイルにダンプするのに役立ちます)。

public static string Debugify(this DbParameterCollection parameters) {
    List<string> ParameterValuesList = new List<string>();

    foreach (DbParameter Parameter in parameters) {
        string ParameterName, ParameterValue;
        ParameterName = Parameter.ParameterName;

        if (Parameter.Direction == ParameterDirection.ReturnValue)
            continue;

        if (Parameter.Value == null || Parameter.Value.Equals(DBNull.Value))
            ParameterValue = "NULL";
        else
        {
            switch (Parameter.DbType)
            {
                case DbType.String:
                case DbType.Date:
                case DbType.DateTime:
                case DbType.Guid:
                case DbType.Xml:
                    ParameterValue
                        = "'" + Parameter
                                .Value
                                .ToString()
                                .Replace(Environment.NewLine, "")
                                .Left(80, "...") + "'"; // Left... is another nice one
                    break;

                default:
                    ParameterValue = Parameter.Value.ToString();
                    break;
            }

            if (Parameter.Direction != ParameterDirection.Input)
                ParameterValue += " " + Parameter.Direction.ToString();
        }

        ParameterValuesList.Add(string.Format("{0}={1}", ParameterName, ParameterValue));
    }

    return string.Join(", ", ParameterValuesList.ToArray());
}

結果の例:

Log.DebugFormat("EXEC {0} {1}", procName, params.Debugify);
// EXEC spProcedure @intID=5, @nvName='Michael Haren', @intRefID=11 OUTPUT

DB 呼び出しの後にこれを呼び出すと、出力パラメーターも入力されることに注意してください。これを SP 名を含む行で呼び出して、デバッグのために呼び出しを SSMS にコピー/貼り付けできるようにします。


これらにより、コードを中断することなく、ログ ファイルをきれいに簡単に生成できます。

于 2009-06-05T04:34:50.937 に答える
9

base-36 文字列 (!) を整数に変換する拡張メソッドのペア:

public static int ToBase10(this string base36)
{
    if (string.IsNullOrEmpty(base36))
        return 0;
    int value = 0;
    foreach (var c in base36.Trim())
    {
        value = value * 36 + c.ToBase10();
    }
    return value;
}

public static int ToBase10(this char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';
    c = char.ToUpper(c);
    if (c >= 'A' && c <= 'Z')
        return c - 'A' + 10;
    return 0;
}

(何人かの天才は、数値をデータベースに格納する最善の方法は文字列にエンコードすることだと判断しました。10 進数はスペースを取りすぎます。16 進数の方が優れていますが、文字 GZ は使用しません。したがって、基数 16 を基数 36 に拡張することは明らかです! )

于 2009-06-05T04:25:57.990 に答える
7

ADO.NET オブジェクトとメソッドを簡単に操作できるように、一連の拡張メソッドを作成しました。

1 つの命令で DbConnection から DbCommand を作成します。

    public static DbCommand CreateCommand(this DbConnection connection, string commandText)
    {
        DbCommand command = connection.CreateCommand();
        command.CommandText = commandText;
        return command;
    }

パラメータを DbCommand に追加します。

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType)
    {
        DbParameter p = AddParameter(command, name, dbType, 0, ParameterDirection.Input);
        return p;
    }

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, object value)
    {
        DbParameter p = AddParameter(command, name, dbType, 0, ParameterDirection.Input);
        p.Value = value;
        return p;
    }

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size)
    {
        return AddParameter(command, name, dbType, size, ParameterDirection.Input);
    }

    public static DbParameter AddParameter(this DbCommand command, string name, DbType dbType, int size, ParameterDirection direction)
    {
        DbParameter parameter = command.CreateParameter();
        parameter.ParameterName = name;
        parameter.DbType = dbType;
        parameter.Direction = direction;
        parameter.Size = size;
        command.Parameters.Add(parameter);
        return parameter;
    }

index ではなく名前で DbDataReader フィールドにアクセスします。

    public static DateTime GetDateTime(this DbDataReader reader, string name)
    {
        int i = reader.GetOrdinal(name);
        return reader.GetDateTime(i);
    }

    public static decimal GetDecimal(this DbDataReader reader, string name)
    {
        int i = reader.GetOrdinal(name);
        return reader.GetDecimal(i);
    }

    public static double GetDouble(this DbDataReader reader, string name)
    {
        int i = reader.GetOrdinal(name);
        return reader.GetDouble(i);
    }

    public static string GetString(this DbDataReader reader, string name)
    {
        int i = reader.GetOrdinal(name);
        return reader.GetString(i);
    }

    ...

別の (無関係な) 拡張メソッドを使用すると、WinForms フォームとコントロールで (WPF のように) DragMove 操作を実行できます。こちらを参照してください

于 2009-06-05T08:44:14.310 に答える
5

これは、イベントを発生させる前に null チェックを集中化するための拡張メソッドです。

public static class EventExtension
{
    public static void RaiseEvent<T>(this EventHandler<T> handler, object obj, T args) where T : EventArgs
    {
        EventHandler<T> theHandler = handler;

        if (theHandler != null)
        {
            theHandler(obj, args);
        }
    }
}
于 2009-08-23T00:40:56.120 に答える
5

ここにある拡張メソッドのほとんどの例は、ベスト プラクティスに反しています。拡張メソッドは強力ですが、慎重に使用する必要があります。私の経験では、古い学校の構文を使用した静的なヘルパー/ユーティリティ クラスは、これらのほとんどに一般的に適しています。

Enum の拡張メソッドについては、メソッドを持つことができないため、言いたいことがあります。Enum と同じ名前空間および同じアセンブリで定義すると、それらは透過的に機能します。

于 2009-06-05T08:29:37.177 に答える
5

多くの場合、Enum 値に基づいてユーザー フレンドリな値を表示する必要がありましたが、カスタム属性ルートはあまりエレガントに見えなかったため、行きたくありませんでした。

この便利な拡張メソッドを使用すると:

public static string EnumValue(this MyEnum e) {
    switch (e) {
        case MyEnum.First:
            return "First Friendly Value";
        case MyEnum.Second:
            return "Second Friendly Value";
        case MyEnum.Third:
            return "Third Friendly Value";
    }
    return "Horrible Failure!!";
}

私がすることができます:

Console.WriteLine(MyEnum.First.EnumValue());

わーい!

于 2009-09-13T06:34:23.590 に答える
5

非常に単純ですが、プロジェクトの 100 億回の完全な結果セットからページを取得するので、これは特に便利です。

public static class QueryableExtensions
{
    public static IQueryable<T> Page(this IQueryable<T> query, int pageNumber, int pageSize)
    {
        int skipCount = (pageNumber-1) * pageSize;
        query = query.Skip(skipCount);
        query = query.Take(pageSize);

        return query;
    }
}
于 2009-06-06T03:28:11.300 に答える
3

これは信じられないほど単純ですが、私がよく行うチェックなので、拡張メソッドを作成することになりました。私のお気に入りの拡張メソッドは、このような非常にシンプルで単純なもの、またはイベントを発生させるための Taylor L の拡張メソッドのようなものです。

public static bool IsNullOrEmpty(this ICollection e)
{
    return e == null || e.Count == 0;
}
于 2009-09-13T06:42:52.840 に答える
2

私は多くの Java を C# に変換しています。メソッドの多くは、大文字化またはその他の小さな構文の違いのみが異なります。したがって、次のようなJavaコード

myString.toLowerCase();

コンパイルされませんが、拡張メソッドを追加することによって

public static void toLowerCase(this string s)
{
    s.ToLower();
}

私はすべてのメソッドをキャッチできます (そして、良いコンパイラはとにかくこれをインライン化すると思いますか?)。

確かに、作業がはるかに簡単になり、信頼性が向上しました。(@Yuriy に感謝します - 回答を参照: Java と C# の StringBuilder の違い) 提案について。

于 2009-10-11T14:22:37.910 に答える
2

私が頻繁に使用する別のセットは、IDictionary メソッドを結合するためのものです。

    public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, Func<TValue> valueThunk)
    {
        TValue v = d.Get(key);
        if (v == null)
        {
            v = valueThunk();
            d.Add(key, v);
        }
        return v;
    }
    public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, TValue coalesce)
    {
        return Get(d, key, () => coalesce);
    }

そして、一般的にコレクションを操作する場合:

    public static IEnumerable<T> AsCollection<T>(this T item)
    {
        yield return item;
    }

次に、ツリーのような構造の場合:

    public static LinkedList<T> Up<T>(this T node, Func<T, T> parent)
    {
        var list = new LinkedList<T>();
        node.Up(parent, n => list.AddFirst(n));
        return list;
    }

したがって、次のようなクラスを簡単にトラバースして操作できます。

class Category
{
    public string Name { get; set; }
    public Category Parent { get; set; }
}

次に、関数合成を容易にし、C# でのプログラミング方法をより F# に近づけるために、次のようにします。

public static Func<T, T> Func<T>(this Func<T, T> f)
{
    return f;
}
public static Func<T1, R> Compose<T1, T2, R>(this Func<T1, T2> f, Func<T2, R> g)
{
    return x => g(f(x));
}
于 2009-06-11T16:36:59.940 に答える
2

より機能的なコンビネータ コードを許可するには:

    public static Func<T, R> TryCoalesce<T, R>(this Func<T, R> f, R coalesce)
    {
        return x =>
            {
                try
                {
                    return f(x);
                }
                catch
                {
                    return coalesce;
                }
            };
    }
    public static TResult TryCoalesce<T, TResult>(this Func<T, TResult> f, T p, TResult coalesce)
    {
        return f.TryCoalesce(coalesce)(p);
    }

次に、次のように書くことができます。

    public static int ParseInt(this string str, int coalesce)
    {
        return TryCoalesce(int.Parse, str, coalesce);
    }
于 2009-06-10T23:08:54.590 に答える
1

日(この場合は週の最初の日は月曜日)を指定するビットマスクをDayOfWeek列挙型の列挙にデコードするintの拡張メソッド:

public static IEnumerable<DayOfWeek> Days(this int dayMask)
{
    if ((dayMask & 1) > 0) yield return DayOfWeek.Monday;
    if ((dayMask & 2) > 0) yield return DayOfWeek.Tuesday;
    if ((dayMask & 4) > 0) yield return DayOfWeek.Wednesday;
    if ((dayMask & 8) > 0) yield return DayOfWeek.Thursday;
    if ((dayMask & 16) > 0) yield return DayOfWeek.Friday;
    if ((dayMask & 32) > 0) yield return DayOfWeek.Saturday;
    if ((dayMask & 64) > 0) yield return DayOfWeek.Sunday;
}
于 2009-06-05T04:21:14.603 に答える
1

私はどこでもこれをしなければならないのが嫌いです:

DataSet ds = dataLayer.GetSomeData(1, 2, 3);
if(ds != null){
    if(ds.Tables.Count > 0){
        DataTable dt = ds.Tables[0];
        foreach(DataRow dr in dt.Rows){
            //Do some processing
        }
    }
}

代わりに、私は通常、次の拡張メソッドを使用します。

public static IEnumerable<DataRow> DataRows(this DataSet current){
    if(current != null){
        if(current.Tables.Count > 0){
            DataTable dt = current.Tables[0];
            foreach(DataRow dr in dt.Rows){
                yield return dr;
            }
        }
    }
}

したがって、最初の例は次のようになります。

foreach(DataRow row in ds.DataRows()){
    //Do some processing
}

イェーイ、拡張メソッド!

于 2009-11-26T01:59:30.847 に答える
1

ここに私が書いた別のものがあります:

    public static class StringExtensions
    {
        /// <summary>
        /// Returns a Subset string starting at the specified start index and ending and the specified end
        /// index.
        /// </summary>
        /// <param name="s">The string to retrieve the subset from.</param>
        /// <param name="startIndex">The specified start index for the subset.</param>
        /// <param name="endIndex">The specified end index for the subset.</param>
        /// <returns>A Subset string starting at the specified start index and ending and the specified end
        /// index.</returns>
        public static string Subsetstring(this string s, int startIndex, int endIndex)
        {
            if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex", "Must be positive.");
            if (endIndex < 0) throw new ArgumentOutOfRangeException("endIndex", "Must be positive.");
            if (startIndex > endIndex) throw new ArgumentOutOfRangeException("endIndex", "Must be >= startIndex.");
            return s.Substring(startIndex, (endIndex - startIndex));
        }

        /// <summary>
        /// Finds the specified Start Text and the End Text in this string instance, and returns a string
        /// containing all the text starting from startText, to the begining of endText. (endText is not
        /// included.)
        /// </summary>
        /// <param name="s">The string to retrieve the subset from.</param>
        /// <param name="startText">The Start Text to begin the Subset from.</param>
        /// <param name="endText">The End Text to where the Subset goes to.</param>
        /// <param name="ignoreCase">Whether or not to ignore case when comparing startText/endText to the string.</param>
        /// <returns>A string containing all the text starting from startText, to the begining of endText.</returns>
        public static string Subsetstring(this string s, string startText, string endText, bool ignoreCase)
        {
            if (string.IsNullOrEmpty(startText)) throw new ArgumentNullException("startText", "Must be filled.");
            if (string.IsNullOrEmpty(endText)) throw new ArgumentNullException("endText", "Must be filled.");
            string temp = s;
            if (ignoreCase)
            {
                temp = s.ToUpperInvariant();
                startText = startText.ToUpperInvariant();
                endText = endText.ToUpperInvariant();
            }
            int start = temp.IndexOf(startText);
            int end = temp.IndexOf(endText, start);
            return Subsetstring(s, start, end);
        }
    }

これの背後にある動機は単純でした。組み込みの Substring メソッドがパラメーターとして startindex と length をどのように受け取ったか、常に私を悩ませていました。startindex と endindex を実行すると、常により便利になります。だから、私は自分自身を転がしました:

使用法:

        string s = "This is a tester for my cool extension method!!";
        s = s.Subsetstring("tester", "cool",true);

Subsetstring を使用しなければならなかった理由は、Substring のオーバーロードが既に 2 つの int を使用していたためです。誰かいい名前あったら教えてください!!

于 2009-06-05T05:05:29.040 に答える
1

System.Linq.Enumerable私が最もよく使用する拡張メソッドは、クラス内のものでなければなりません。

そして、 MoreLinqで見つけることができる、そのリストの優れた便利な拡張機能です。

于 2009-06-05T08:02:37.997 に答える
1

私が主に使用するいくつかの拡張機能。最初のセットはオブジェクト拡張で、実際には変換専用です。

public static class ObjectExtension
{
    public static T As<T>(this object value)
    {
        return (value != null && value is T) ? (T)value : default(T);
    }

    public static int AsInt(this string value)
    {
        if (value.HasValue())
        {
            int result;

            var success = int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out result);

            if (success)
            {
                return result;
            }
        }

        return 0;
    }

    public static Guid AsGuid(this string value)
    {
        return value.HasValue() ? new Guid(value) : Guid.Empty;
    }
}

文字列拡張子

public static class StringExtension
{
    public static bool HasValue(this string value)
    {
        return string.IsNullOrEmpty(value) == false;
    }

    public static string Slug(this string value)
    {
        if (value.HasValue())
        {
            var builder = new StringBuilder();
            var slug = value.Trim().ToLower();

            foreach (var c in slug)
            {
                switch (c)
                {
                    case ' ':
                        builder.Append("-");
                        break;
                    case '&':
                        builder.Append("and");
                        break;
                    default:

                        if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') && c != '-')
                        {
                            builder.Append(c);
                        }

                        break;
                }
            }

            return builder.ToString();
        }

        return string.Empty;
    }

    public static string Truncate(this string value, int limit)
    {
        return (value.Length > limit) ? string.Concat(value.Substring(0, Math.Min(value.Length, limit)), "...") : value;
    }
}

そして最後はいくつかの列挙型拡張です

public static class EnumExtensions
{
    public static bool Has<T>(this Enum source, params T[] values)
    {
        var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);

        foreach (var i in values)
        {
            var mask = Convert.ToInt32(i, CultureInfo.InvariantCulture);

            if ((value & mask) == 0)
            {
                return false;
            }
        }

        return true;
    }

    public static bool Has<T>(this Enum source, T values)
    {
        var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
        var mask = Convert.ToInt32(values, CultureInfo.InvariantCulture);

        return (value & mask) != 0;
    }

    public static T Add<T>(this Enum source, T v)
    {
        var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
        var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture);

        return Enum.ToObject(typeof(T), value | mask).As<T>();
    }

    public static T Remove<T>(this Enum source, T v)
    {
        var value = Convert.ToInt32(source, CultureInfo.InvariantCulture);
        var mask = Convert.ToInt32(v, CultureInfo.InvariantCulture);

        return Enum.ToObject(typeof(T), value & ~mask).As<T>();
    }

    public static T AsEnum<T>(this string value)
    {
        try
        {
            return Enum.Parse(typeof(T), value, true).As<T>();
        }
        catch
        {
            return default(T);
        }
    }
}
于 2009-06-07T09:00:45.513 に答える
1

これは、最初に単一の要素が追加された配列を作成します。

public static T[] Prepend<T>(this T[] array, T item)
{
    T[] result = new T[array.Length + 1];
    result[0] = item;
    Array.Copy(array, 0, result, 1, array.Length);
    return result;
}

string[] some = new string[] { "foo", "bar" };
...
some = some.Prepend("baz"); 

そして、これは、式を正方形に変換する必要があるときに役立ちます。

public static double Sq(this double arg)
{
    return arg * arg;
}

(x - x0).Sq() + (y - y0).Sq() + (z - z0).Sq()
于 2009-06-05T05:00:06.490 に答える
1

ここで言及した、私が使用しているものはいくつかあります。

于 2009-06-05T10:49:25.663 に答える
1

文字列ユーティリティの私自身の個人的なコレクションからの私のお気に入りは、TryParse メソッドを持つ任意の型の文字列から厳密に型指定された値を解析するものです。

public static class StringUtils
{
    /// <summary>
    /// This method will parse a value from a string.
    /// If the string is null or not the right format to parse a valid value,
    /// it will return the default value provided.
    /// </summary>
    public static T To<t>(this string value, T defaultValue)
        where T: struct
    {
        var type = typeof(T);
        if (value != null)
        {
            var parse = type.GetMethod("TryParse", new Type[] { typeof(string), type.MakeByRefType() });
            var parameters = new object[] { value, default(T) };
            if((bool)parse.Invoke(null, parameters))
                return (T)parameters[1];
        }
        return defaultValue;
    }

    /// <summary>
    /// This method will parse a value from a string.
    /// If the string is null or not the right format to parse a valid value,
    /// it will return the default value for the type.
    /// </summary>
    public static T To<t>(this string value)
        where T : struct
    {
        return value.To<t>(default(T));
    }
}

クエリ文字列から厳密に型指定された情報を取得するのに最適です。

var value = Request.QueryString["value"].To<int>();
于 2009-11-04T15:22:51.323 に答える
1

かっこいい、大好きなエクステンション!

ここにいくつかあります。

これは月の最後の日付を取得します。

<System.Runtime.CompilerServices.Extension()> _
    Public Function GetLastMonthDay(ByVal Source As DateTime) As DateTime
        Dim CurrentMonth As Integer = Source.Month
        Dim MonthCounter As Integer = Source.Month
        Dim LastDay As DateTime
        Dim DateCounter As DateTime = Source

        LastDay = Source

        Do While MonthCounter = CurrentMonth
            DateCounter = DateCounter.AddDays(1)
            MonthCounter = DateCounter.Month

            If MonthCounter = CurrentMonth Then
                LastDay = DateCounter
            End If
        Loop

        Return LastDay
    End Function

これらの 2 つは、リフレクションを少し簡単にします。

 <System.Runtime.CompilerServices.Extension()> _
    Public Function GetPropertyValue(Of ValueType)(ByVal Source As Object, ByVal PropertyName As String) As ValueType
        Dim pInfo As System.Reflection.PropertyInfo

        pInfo = Source.GetType.GetProperty(PropertyName)

        If pInfo Is Nothing Then
            Throw New Exception("Property " & PropertyName & " does not exists for object of type " & Source.GetType.Name)
        Else
            Return pInfo.GetValue(Source, Nothing)
        End If
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Function GetPropertyType(ByVal Source As Object, ByVal PropertyName As String) As Type
        Dim pInfo As System.Reflection.PropertyInfo

        pInfo = Source.GetType.GetProperty(PropertyName)

        If pInfo Is Nothing Then
            Throw New Exception("Property " & PropertyName & " does not exists for object of type " & Source.GetType.Name)
        Else
            Return pInfo.PropertyType
        End If
    End Function
于 2009-06-05T06:14:01.327 に答える
1

私はこれが好きです。これは String.Split メソッドのバリエーションであり、分割文字が実際の文字列にあることが意図されている場合に、エスケープ文字を使用して分割を抑制することができます。

于 2009-06-05T03:55:04.623 に答える
0

String.formatは静的であってはなりません。だから私はfrmtと呼ばれる拡張メソッドを使用します:

<Extension()> Public Function frmt(ByVal format As String,
                                   ByVal ParamArray args() As Object) As String
    If format Is Nothing Then Throw New ArgumentNullException("format")
    Return String.Format(format, args)
End Function

バイナリライターを作成せずにバイトストリームに数値を読み書きしたい場合(技術的には、ライターでラップした後に生のストリームを変更することは想定されていません):

<Extension()> Public Function Bytes(ByVal n As ULong,
                                    ByVal byteOrder As ByteOrder,
                                    Optional ByVal size As Integer = 8) As Byte()
    Dim data As New List(Of Byte)
    Do Until data.Count >= size
        data.Add(CByte(n And CULng(&HFF)))
        n >>= 8
    Loop
    Select Case byteOrder
        Case ByteOrder.BigEndian
            Return data.ToArray.reversed
        Case ByteOrder.LittleEndian
            Return data.ToArray
        Case Else
            Throw New ArgumentException("Unrecognized byte order.")
    End Select
End Function
<Extension()> Public Function ToULong(ByVal data As IEnumerable(Of Byte),
                                      ByVal byteOrder As ByteOrder) As ULong
    If data Is Nothing Then Throw New ArgumentNullException("data")
    Dim val As ULong
    Select Case byteOrder
        Case ByteOrder.LittleEndian
            data = data.Reverse
        Case ByteOrder.BigEndian
            'no change required
        Case Else
            Throw New ArgumentException("Unrecognized byte order.")
    End Select
    For Each b In data
        val <<= 8
        val = val Or b
    Next b
    Return val
End Function
于 2009-06-05T05:24:42.293 に答える
0

私はおそらくそれらを制約されたタイプに最もよく使用します。

何かのようなもの:

public class Gallons
{
    private int m_gallons;

    public Gallons(int count)
    {
        if(count < 0)
            throw new ArgumentException("Cannot have negative gallons");
        m_gallons = count;
    }

    static public Gallons operator + (Gallons left, Gallons right)
    {
        return new Gallons(left.m_gallons + right.m_gallons);
    }
    public override string ToString()
    {
        return m_gallons.ToString();
    }
}
public class Feet
{
    private int m_feet;

    public Feet(int count)
    {
        if(count < 0)
            throw new ArgumentException("Cannot have negative feet");
        m_feet = count;
    }

    static public Feet operator +(Feet left, Feet right)
    {
        return new Feet(left.m_feet + right.m_feet);
    }
    public override string ToString()
    {
        return m_feet.ToString();
    }
}

public static class Conversions
{
    static public Feet Feet(this int i)
    {
        return new Feet(i);
    }
    static public Gallons Gallons(this int i)
    {
        return new Gallons(i);
    }
}

public class Test
{
    static public int Main(string[] args)
    {
        System.Console.WriteLine(2.Feet() + 3.Feet()); // 5
        System.Console.WriteLine(3.Gallons() + 4.Gallons()); // 7
        System.Console.WriteLine(2.Feet() + 3.Gallons()); // doesn't compile - can't add feet to gallons!
        return 0;
    }
}
于 2010-03-06T00:49:14.300 に答える
0

これが私が最近仕事で書き、ブログに書いたものです:

http://crazorsharp.blogspot.com/2009/03/cool-ienumberable-extension-method_25.html

基本的にはIEnumerable.ToHtmlTable();です。

于 2009-06-05T04:12:13.980 に答える
0

MVCプロジェクトのclass-name-to-upper-case-urlの問題を解決するために、次の自動操縦を行います。

public static class RouteCollectionExt
{
    public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults)
    {
        var route = new LowercaseRoute(url, new RouteValueDictionary(defaults), new MvcRouteHandler());

        routes.Add(name, route);

        return route;
    }

    private class LowercaseRoute : Route
    {
        public LowercaseRoute(string url, IRouteHandler routeHandler)
            : base(url, routeHandler) { }

        public LowercaseRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
            : base(url, defaults, routeHandler) { }

        public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
            : base(url, defaults, constraints, routeHandler) { }

        public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
            : base(url, defaults, constraints, dataTokens, routeHandler) { }

        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            var path = base.GetVirtualPath(requestContext, values);

            if (path != null)
            {
                path.VirtualPath = path.VirtualPath.ToLowerInvariant();
            }

            return path;
        }
    }  
}

使用法:

routes.MapRouteLowercase(
  "Default",
  "{controller}/{action}/{id}",
  new { controller = "Home", action = "Index", id = "" } 
);
于 2009-06-05T10:50:31.933 に答える
0

これは、指定されたアイテムを最初に取得するようにシーケンスをシフトします。たとえば、曜日を取得してシフトし、シーケンスの最初の日が現在のカルチャの最初の曜日になるように使用しました。

    /// <summary>
    /// Shifts a sequence so that the given <paramref name="item"/> becomes the first. 
    /// Uses the specified equality <paramref name="comparer"/> to find the item.
    /// </summary>
    /// <typeparam name="TSource">Type of elements in <paramref name="source"/>.</typeparam>
    /// <param name="source">Sequence of elements.</param>
    /// <param name="item">Item which will become the first.</param>
    /// <param name="comparer">Used to find the first item.</param>
    /// <returns>A shifted sequence. For example Shift({1,2,3,4,5,6}, 3) would become {3,4,5,6,1,2}. </returns>
    public static IEnumerable<TSource> Shift<TSource>(this IEnumerable<TSource> source, TSource item, IEqualityComparer<TSource> comparer)
    {
        var queue = new Queue<TSource>();
        bool found = false;

        foreach (TSource e in source)
        {
            if (!found && comparer.Equals(item, e))
                found = true;

            if (found)
                yield return e;
            else
                queue.Enqueue(e);
        }

        while (queue.Count > 0)
            yield return queue.Dequeue();
    }


    /// <summary>
    /// Shifts a sequence so that the given item becomes the first. 
    /// Uses the default equality comparer to find the item.
    /// </summary>
    /// <typeparam name="TSource">Type of elements in <paramref name="source"/>.</typeparam>
    /// <param name="source">Sequence of elements.</param>
    /// <param name="element">Element which will become the first.</param>
    /// <returns>A shifted sequence. For example Shift({1,2,3,4,5,6}, 3) would become {3,4,5,6,1,2}. </returns>
    public static IEnumerable<TSource> Shift<TSource>(this IEnumerable<TSource> source, TSource element)
    {
        return Shift(source, element, EqualityComparer<TSource>.Default);
    }
于 2009-06-05T07:49:38.820 に答える
0

Entity Frameworkで作業し、これに似たコード行を何度も使用したことがありますか?

_context.EmployeeSet.Include("Department")
    .Include("Manager").Include( ... ).Select();

これを行う方が簡単ではありませんか:

_context.EmployeeSet.IncludeCommonReferenceses().Select();

`

internal static class ObjectContextExtensions
{
    internal static ObjectQuery<Employee> IncludeCommonReferenceses(this ObjectQuery<Employee> employeeSet)
    {
        return employeeSet.Include(GetPropertyName<Employee>(e => e.Department))
           .Include(GetPropertyName<Employee>(e => e.Manager)).Include( ... );
    }

    private static string GetPropertyName<T>(Expression<Func<T, object>> subSelector)
    {
        return ((MemberExpression)subSelector.Body).Member.Name;
    }
}

リフレクションを繰り返し使用しないように、プロパティ名を const に保存することをお勧めします。

于 2009-10-19T07:20:56.967 に答える
0

指定された fileinfo クラスの指定されたプロパティを別のプロパティと比較します。

    public static bool compare(this FileInfo F1,FileInfo F2,string propertyName)
    {
        try
        {
            System.Reflection.PropertyInfo p1 = F1.GetType().GetProperty(propertyName);
            System.Reflection.PropertyInfo p2 = F2.GetType().GetProperty(propertyName);

                if (p1.GetValue(F1, null) == p2.GetValue(F1, null))
                {
                    return true;
                }

        }
        catch (Exception ex)
        {
            return false;
        }

        return false;
    }
于 2010-02-26T07:00:41.153 に答える
0
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string guid1 = "936DA01F-9ABD-4d9d-80C7-02AF85C822A8";
            string guid2 = "936DA01F-9ABD-4d9d-80C7-02AF85C822A";
            Console.WriteLine("guid1: {0}", guid1.IsGuid());
            Console.WriteLine("guid2: {0}", guid2.IsGuid());
            Console.ReadLine();
        }
    }

    public static class GuidUtility
    {
        /// <summary>
        /// Determines if string is legitimate GUID
        /// </summary>       
        public static Boolean IsGuid(this String s)
        {
            string pattern = @"^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$";
            Regex regex = new Regex(pattern);
            return regex.IsMatch(s);
        }
    }
}
于 2009-06-07T02:16:19.473 に答える
0

これは、ストリームから別のストリームにコピーするためによく使用するものです。特に、ものを MemoryStream にコピーする場合に使用します。

public static void CopyStream(this Stream destination, Stream source)
    {
        if (source.CanSeek)
        {
            source.Position = 0;
        }
        int Length = 64000;
        Byte[] buffer = new Byte[Length];
        int bytesRead = source.Read(buffer, 0, Length);
        // write the required bytes
        while (bytesRead > 0)
        {
            destination.Write(buffer, 0, bytesRead);
            bytesRead = source.Read(buffer, 0, Length);
        }
    }

実装:

MemoryStream result = new MemoryStream();
Stream s = new FileStream(tempDocFile, FileMode.Open);

result.CopyStream(s);

s.Close();
于 2010-02-26T14:48:17.390 に答える
0

私はこれらの 2 つを書きませんでしたが、書いておけばよかったのにと思います。http://lostechies.com/jimmybogard/2009/10/16/more-missing-linq-operators/にあります

追加

public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element)
{
    using (IEnumerator<TSource> e1 = source.GetEnumerator())
        while (e1.MoveNext())
            yield return e1.Current;

    yield return element;
}

プリペンド

public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource element)
{
    yield return element;

    using (IEnumerator<TSource> e1 = source.GetEnumerator())
        while (e1.MoveNext())
            yield return e1.Current;
}
于 2011-09-12T14:52:54.873 に答える
0

これらのいくつかはすでに投稿されていますが、私はこれらのスレッドをいくつか見てきましたが、有用なものの現実と投票が一致していないことを言いたかっただけです. IMO、これは本当に最も便利な拡張メソッドのリストです

someCollection.ForEach(i => i.DoSomething());

これは、組み込みの foreach ステートメントを置き換えるため、非常に便利です。

7.CreateSequence();

これは、0 から 6 までのシーケンスを作成するだけです。開始点とステップを指定するなど、他のバージョンが存在する可能性があります。これは、for ループを置き換えるため、2 番目に便利な関数です。これは Enumerable.Range 関数を複製していると言う人もいますが、これは本当ですが、私が linq で気に入っていることの 1 つは左から右への順序であるため、次のようなことができます。

myCollection.Where(i => i.Something == somethingElse).Count().CreateSequence(). do something else

次に便利なのは、CastTo と As です。ここでも組み込み機能が複製されますが、左から右への順序は維持されます。CastTo は単一のオブジェクトで機能するという点で CastTo とは異なることに注意してください。

myObject.CastTo<Person>().DoSomething()
myObject.As<Person>()

次に、SplitAsEnumerable があります。これは分割と同じように機能しますが、一度にすべてをメモリにロードするわけではありません。これは、大きなファイルを解析するのに最適です。文字列またはストリームで機能します。

myFileStream.SplitAsEnumerable("\r\n").Select(line => line.SplitAsEnumerable(","))

最後の 1 つは、コレクションを文字列に変換する方法です。これは、画面に何かを表示したり、ファイルに書き込んだりするのに最適です。例えば:

myTextBox.Text = "Top 3 scorers are " + myCollection.OrderBy(i => i.Score).Take(3).FlattenToString(i => i.Score.ToString(), ", ");
于 2011-08-30T23:48:05.127 に答える
0

マルチスレッドの WPF アプリケーション (たとえば、ソケットやタイマーを使用している場合) では、GUI スレッドを呼び出して WPF 要素の属性を変更しなければならないことがよくあります。これは、特にすべてのメソッドに対して実行する必要があるため、見苦しい肥大化したコードです。そのため、この拡張メソッドを作成しました。

    /// <summary>
    /// Invoke the element's thread using a dispatcher. This is needed for changing WPF element attributes.
    /// </summary>
    /// <param name="dispatcherObject">The element of which to use the thread.</param>
    /// <param name="action">The action to do with the invoked thread.</param>
    /// <param name="dispatcherPriority">The priority of this action.</param>
    public static void DoInvoked(this System.Windows.Threading.DispatcherObject dispatcherObject, Action action, System.Windows.Threading.DispatcherPriority dispatcherPriority = System.Windows.Threading.DispatcherPriority.Render)
    {
        if (System.Threading.Thread.CurrentThread == dispatcherObject.Dispatcher.Thread)
        {
            action();
        }
        else
        {
            dispatcherObject.Dispatcher.BeginInvoke(action, dispatcherPriority, null);
        }
    }

実装:

public partial class MainWindow : Window
{
    ... other code ...
    void updateTime(object sender, ElapsedEventArgs e)
    {
        this.DoInvoked(() => textBoxStatus.Text = "Done.");
    }
}
于 2010-03-06T00:29:15.943 に答える