developer tip

지금까지 본 확장 방법의 가장 좋은 또는 가장 흥미로운 사용은 무엇입니까?

optionbox 2020. 10. 29. 08:03
반응형

지금까지 본 확장 방법의 가장 좋은 또는 가장 흥미로운 사용은 무엇입니까?


저는 확장 방법을 정말 좋아하기 시작했습니다. 그녀가 정말 마음을 사로 잡는 방법을 우연히 발견했거나 영리한 것을 찾은 사람이 있는지 궁금합니다.

내가 오늘 쓴 예 :

다른 사용자의 댓글로 인해 수정 됨 :

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());
}

다른 예를보고 싶어요! 즐겨!


전체 솔루션은 너무 커서 여기에 넣을 수 없지만 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

이것은 최근에 나로부터 약간의 플레이를 얻고있는 것입니다.

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);
}

나는 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); }
}

강력한 유형이며 실제로 값을 변경하는 속성에 대해서만 이벤트를 발생시킵니다.


이것은 정확히 영리하지는 않지만 ---- OrDefault 메서드를 수정하여 나중에 코드에서 null을 확인하는 대신 기본 항목을 인라인으로 지정할 수 있습니다.

    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;
    }

놀랍도록 간단하지만 실제로 null 검사를 정리하는 데 도움이됩니다. UI가 토너먼트 시스템 또는 게임 플레이어 슬롯과 같은 X 항목 목록을 예상하고 "빈 좌석"을 표시하려는 경우에 가장 적합합니다.

용법:

    return jediList.SingleOrDefault( 
                 j => j.LightsaberColor == "Orange", 
               new Jedi() { LightsaberColor = "Orange", Name = "DarthNobody");

여기 제가 함께 해킹 한 것이 있으니 자유롭게 구멍을 뚫 으세요. (순서화 된) 정수 목록을 가져 와서 연속 범위의 문자열 목록을 반환합니다. 예 :

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"이됩니다. 사용자에게 강의가 진행되는 학업 주간 범위에 대한 간략한 설명을 제공합니다.


내가 사용하고 싶은 두 가지는 내가 작성한 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에 대해 몇 가지 중요한 개선을했습니다. 세 번째 항목마다 3 백만 개의 항목이 제거되는 경우 새 버전은 RemoveWhere의 여러 초 (기다리는 데 지쳤습니다)와 달리 ~ 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);
            }
        }
    }

.Debugify개체를 로그 파일에 덤프하는 데 유용한 다양한 확장 메서드가 있습니다. 예를 들어, 여기에 내 사전 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에 대한 것입니다 (데이터베이스 호출을 로그 파일에 덤프하는 데 유용함).

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에 복사 / 붙여 넣기 할 수 있습니다.


이것들은 내 코드를 방해하지 않고 내 로그 파일을 예쁘고 쉽게 생성 할 수있게합니다.


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;
}

(일부 천재는 데이터베이스에 숫자를 저장하는 가장 좋은 방법은 문자열로 인코딩하는 것이라고 결정했습니다. 소수는 너무 많은 공간을 차지합니다. 16 진수가 더 좋지만 문자 GZ를 사용하지 않습니다. 따라서 분명히 base-16을 base-36으로 확장합니다! )


ADO.NET 개체 및 메서드를보다 쉽게 ​​조작 할 수 있도록 일련의 확장 메서드를 작성했습니다.

하나의 명령으로 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;
    }

색인이 아닌 이름으로 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 양식 및 컨트롤에서 DragMove 작업 (예 : WPF)을 수행 할 수 있습니다 . 여기를 참조하십시오 .


여기에서 보는 확장 방법에 대한 대부분의 예는 모범 사례에 위배됩니다. 확장 방법은 강력하지만 드물게 사용해야합니다. 내 경험상 구식 구문을 사용하는 정적 도우미 / 유틸리티 클래스가 일반적으로 대부분의 경우 선호됩니다.

Enum에 대한 확장 메서드에 대해 할 말이 있습니다. 메서드를 가질 수 없기 때문입니다. Enum과 동일한 네임 스페이스 및 동일한 어셈블리에서 정의하면 투명하게 작동합니다.


매우 간단하지만 프로젝트 당 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;
    }
}

종종 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());

예이!


이벤트를 발생시키기 전에 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);
        }
    }
}

이것은 엄청나게 간단하지만 제가 많이하는 수표이기 때문에 결국 확장 방법을 만들었습니다. 제가 가장 좋아하는 확장 방법은 이와 같이 매우 간단하고 간단한 방법이거나 이벤트를 발생시키는 Taylor L의 확장 방법과 같습니다.

public static bool IsNullOrEmpty(this ICollection e)
{
    return e == null || e.Count == 0;
}

보다 기능적인 조합 코드를 허용하려면 다음을 수행하십시오.

    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);
    }

내가 자주 사용하는 또 다른 세트는 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));
}

많은 Java를 C #으로 변환하고 있습니다. 대부분의 메서드는 대문자 또는 기타 작은 구문 차이 만 다릅니다. 따라서 다음과 같은 Java 코드

myString.toLowerCase();

컴파일되지 않고 확장 메서드를 추가하여

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

모든 메서드를 잡을 수 있습니다 (좋은 컴파일러가 어쨌든 이것을 인라인한다고 가정합니까?).

확실히 작업을 훨씬 쉽고 안정적으로 만들었습니다. (@Yuriy에게 감사드립니다-Java의 StringBuilder와 C #의 차이점에 대한 답변 참조 ) 제안에 대해.


나는 이것을 좋아 한다 . 분할 문자가 실제 문자열에 포함되도록 의도 된 경우 이스케이프 문자를 사용하여 분할을 억제 할 수 있도록하는 String.Split 메서드의 변형입니다.


int의 확장 메서드를 사용하여 DayOfWeek 열거 형의 열거 형으로 요일을 지정하는 비트 마스크를 디코딩합니다 (이 경우 첫 번째 요일은 월요일 임).

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;
}

이것은 맨 처음에 추가 된 단일 요소로 배열을 만듭니다.

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()

내가 쓴 또 다른 것이 있습니다.

    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의 오버로드가 이미 두 개의 int를 취하기 때문입니다. 더 나은 이름을 가진 사람이 있으면 알려주세요 !!


멋지고 사랑스러운 확장 기능!

여기에 몇 가지가 있습니다.

이것은 한 달의 마지막 날짜를 가져옵니다.

<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

이 두 가지는 반사를 조금 더 쉽게 만듭니다.

 <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

내가 가장 많이 사용하는 확장 방법은 System.Linq.Enumerable클래스 에있는 방법이어야합니다 .

그리고 그 목록에 대한 훌륭하고 유용한 확장은 MoreLinq 에서 찾을 수 있습니다 .


내가 여기에서 언급 한 몇 가지가 있습니다.


주로 사용하는 확장 기능이 거의 없습니다. 첫 번째 세트는 실제로 변환을위한 객체 확장입니다.

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);
        }
    }
}

StringBuilder를 정기적으로 사용하면 AppendFormat ()과 AppendLine ()을 결합해야 할 필요가 있음을 알 수 있습니다.

public static void AppendFormatLine(this StringBuilder sb, string format, params object[] args)
{
    sb.AppendFormat(format, args);
    sb.AppendLine();
}

또한 응용 프로그램을 VB6에서 C #으로 변환하고 있으므로 다음이 매우 유용합니다.

public static string Left(this string s, int length)
{
    if (s.Length >= length)
        return s.Substring(0, length);
    throw new ArgumentException("Length must be less than the length of the string.");
}
public static string Right(this string s, int length)
{
    if (s.Length >= length)
        return s.Substring(s.Length - length, length);
    throw new ArgumentException("Length must be less than the length of the string.");
}

내 개인 문자열 유틸리티 모음에서 내가 가장 좋아하는 것은 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>();

나는 이것을 어디서나해야하는 것을 싫어한다.

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
}

예, 확장 방법!


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

이것은 주어진 항목을 먼저 얻도록 시퀀스를 이동합니다. 예를 들어 요일을 가져 와서 시퀀스의 첫 번째 날이 현재 문화의 첫 번째 요일이되도록 변경하는 데 사용했습니다.

    /// <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);
    }

참고 URL : https://stackoverflow.com/questions/954198/what-is-the-best-or-most-interesting-use-of-extension-methods-youve-seen

반응형