LINQ를 사용하여 컬렉션의 모든 개체 업데이트


499

LINQ를 사용하여 다음을 수행하는 방법이 있습니까?

foreach (var c in collection)
{
    c.PropertyToSet = value;
}

명확히하기 위해 컬렉션의 각 개체를 반복 한 다음 각 개체의 속성을 업데이트하고 싶습니다.

내 유스 케이스는 블로그 게시물에 대한 의견이 많으며 블로그 게시물의 각 의견을 반복하고 블로그 게시물의 날짜 시간을 +10 시간으로 설정하고 싶습니다. SQL로 할 수는 있지만 비즈니스 계층에 유지하고 싶습니다.


14
흥미로운 질문입니다. 개인적으로 나는 당신이 그것을 어떻게 달성했는지를 선호합니다.
noelicus

8
나는 같은 질문에 대한 답을 찾기 위해 여기에 왔으며, 코드가 간단하고 코드가 적으며 미래 개발자가 OP에서 수행 한 방식으로 이해하는 것이 더 쉽다고 결정했습니다.
Casey Crookston

4
LINQ에서 왜 하시겠습니까?
Caltor

13
이 질문은 잘못된 것을 요구합니다. 유일한 정답은 : LINQ를 사용하여 데이터 소스를 수정하지 마십시오
Tim Schmelter

이 질문에 대한 거의 모든 답변이 새로운 프로그래머의 LINQ 이해에 적극적으로 영향을 미치기 때문에이 질문을 논외 주제로 닫으려고합니다.
Tanveer Badar

답변:


841

당신이 사용할 수 있지만 ForEach확장 방법을, 당신은 당신이 할 수있는 단지 프레임 워크를 사용하려는 경우

collection.Select(c => {c.PropertyToSet = value; return c;}).ToList();

게으른 평가ToList 로 인해 선택을 즉시 평가하려면 이 옵션 이 필요합니다 .


6
그것은 꽤 좋은 솔루션 ... 유일한 이유 때문에 나는 이것을 upvoted I 확장 방법은에 ... 그러나 솔루션은 여전히 꽤 달콤한 것입니다 정확히 이해하는 것이 좀 더 명확하게한다는 것이다처럼
lomaxx

9
컬렉션이 ObservableCollection말이라면 새 목록을 만드는 대신 항목을 변경하는 것이 유용 할 수 있습니다.
Cameron MacFarland

7
@desaivv yeah 이것은 약간의 구문 남용이므로 Resharper는 이에 대해 경고합니다.
Cameron MacFarland

46
IMHO, 이것은 간단한 foreach 루프보다 표현력이 훨씬 낮습니다. ToList ()는 지연 될 수있는 평가를 강제하는 것 외에는 사용되지 않기 때문에 혼동됩니다. 투영은 의도 된 목적으로 사용되지 않기 때문에 혼동됩니다. 오히려 컬렉션의 요소를 반복하고 속성에 액세스하여 업데이트 할 수 있도록하는 데 사용됩니다. 내 마음에있는 유일한 질문은 foreach 루프가 Parallel.ForEach를 사용하여 병렬 처리의 이점을 얻을 수 있는지 여부입니다. 그러나 그것은 다른 질문입니다.
Philippe

37
이 답변은 최악의 방법입니다. 절대 이러지 마
Eric Lippert 17 년

351
collection.ToList().ForEach(c => c.PropertyToSet = value);

36
@SanthoshKumar : 사용collection.ToList().ForEach(c => { c.Property1ToSet = value1; c.Property2ToSet = value2; });
Ε Г И І И О

@CameronMacFarland : 물론 구조체가 불변이기 때문에 그렇지 않습니다. 그러나 당신이 정말로 원한다면, 당신은 이것을 할 수 있습니다 :collection.ToList().ForEach(c => { collection[collection.IndexOf(c)] = new <struct type>() { <propertyToSet> = value, <propertyToRetain> = c.Property2Retain }; });
Ε Г И І И О

11
이것은 새 목록을 작성하는 대신 목록을 업데이트하는 Cameron MacFarland의 답변보다 이점이 있습니다.
Simon Tewsi 2016 년

7
와우,이 답변은 실제로 유용하지 않습니다. 루프를 사용할 수 있도록 새로운 컬렉션 만들기
Tim Schmelter

@SimonTewsi 개체의 모음이므로 목록을 업데이트해야합니다. 컬렉션은 새로 만들어 지지만 컬렉션의 개체는 동일합니다.
Chris

70

나는 이것을하고있다

Collection.All(c => { c.needsChange = value; return true; });

나는 이것이 가장 깨끗한 방법이라고 생각합니다.
wcm

31
이 방법은 확실히 작동하지만 All()확장 방법 의 의도를 위반하여 다른 사람이 코드를 읽을 때 혼동을 일으킬 수 있습니다.
Tom Baxter

각 루프를 사용하는 대신 모두 사용
UJS

2
All ()을 사용하는 것에 대해 약간 오도하더라도 ToList ()를 불필요하게 호출하는 것보다 확실히 이것을 선호합니다.
iupchris10

1
같은 모음을 사용하는 경우 List<>그게있는 ForEach()방법이 작업을 수행 할 수있는 훨씬 덜 비밀 방법입니다. 예ForEach(c => { c.needsChange = value; })
Dan이 Filighting By Firelight

27

실제로 내가 원하는 것을 할 수있는 확장 방법찾았습니다.

public static IEnumerable<T> ForEach<T>(
    this IEnumerable<T> source,
    Action<T> act)
{
    foreach (T element in source) act(element);
    return source;
}

4
nice :) Lomaxx, 예를 추가하여 엿보기가 '액션'(boom tish!)에서 볼 수 있습니다.
Pure.Krome 2009

2
이것은 foreach어떤 이유로 든 -loop 를 피하고 싶을 때 유용한 방법 입니다.
Tim Schmelter

foreach코드 자체에 foreach루프 가 포함되어 있으므로 여전히 피하고 있지 않은
@Rango

@GoldBishop 확실히, 메소드는 루프를 숨 깁니다.
Tim Schmelter

1
: 링크 그것은에서 사용할 수 있습니다, 고장 codewrecks.com/blog/index.php/2008/08/13/... . stackoverflow.com/questions/200574로 연결되는 블로그 주석도 있습니다 . 또한, 최상위 질문 의견은 blogs.msdn.microsoft.com/ericlippert/2009/05/18/…에 연결됩니다 . 아마도 대답은 MSDN을 사용하여 다시 작성하는 것이 더 간단 할 것입니다 (원하는 경우 첫 번째 링크에 크레딧을 줄 수 있음). (!) 참고 : 녹는 해당 기능에 포기하고 추가 결국 비슷한 기능을 가지고 있으며, : stackoverflow.com/a/50224248/799204
sourcejedi을

15

사용하다:

ListOfStuff.Where(w => w.Thing == value).ToList().ForEach(f => f.OtherThing = vauleForNewOtherThing);

이것이 LINQ를 과도하게 사용하고 있는지 확실하지 않지만 특정 조건에 대해 목록의 특정 항목을 업데이트하려고 할 때 효과적이었습니다.


7

이를위한 내장 확장 방법은 없습니다. 하나를 정의하는 것은 상당히 간단합니다. 게시물 맨 아래에는 Iterate라는 정의 된 방법이 있습니다. 그렇게 사용할 수 있습니다

collection.Iterate(c => { c.PropertyToSet = value;} );

반복 소스

public static void Iterate<T>(this IEnumerable<T> enumerable, Action<T> callback)
{
    if (enumerable == null)
    {
        throw new ArgumentNullException("enumerable");
    }

    IterateHelper(enumerable, (x, i) => callback(x));
}

public static void Iterate<T>(this IEnumerable<T> enumerable, Action<T,int> callback)
{
    if (enumerable == null)
    {
        throw new ArgumentNullException("enumerable");
    }

    IterateHelper(enumerable, callback);
}

private static void IterateHelper<T>(this IEnumerable<T> enumerable, Action<T,int> callback)
{
    int count = 0;
    foreach (var cur in enumerable)
    {
        callback(cur, count);
        count++;
    }
}

반복이 필요합니까, Count, Sum, Avg 또는 스칼라 값을 반환하는 다른 기존 확장 방법의 문제점은 무엇입니까?
AnthonyWJones

2
이것은 내가 원하는 것과 아주 가깝지만 조금은 관여합니다. 내가 게시 한 블로그 게시물은 비슷한 구현이지만 코드 줄이 적습니다.
lomaxx

1
IterateHelper가 과도하게 보입니다. 인덱스를 사용하지 않는 과부하는 더 많은 추가 작업을 수행하게됩니다 (콜백을 람다로 변환하여 인덱스를 사용하는 람다로 변환하고 사용되지 않은 수를 유지하십시오). 재사용이 가능하다는 것을 알고 있지만 어쨌든 forloop을 사용하는 것이 효과적이므로 효율적입니다.
Cameron MacFarland

2
@Cameron, IterateHelper는 2 가지 목적을 제공합니다. 1) 단일 구현 및 2) 호출 시간 대 사용시 ArgumentNullException이 발생하도록 허용합니다. C # 반복자는 실행이 지연되어 도우미가 반복 중에 예외가 발생하는 것을 방지합니다.
JaredPar

2
@JaredPar : 반복자를 사용하지 않는 것을 제외하고. 항복 진술이 없습니다.
Cameron MacFarland

7

LINQ 솔루션을 구체적으로 요청했지만이 질문은 꽤 오래되었지만 비 LINQ 솔루션을 게시합니다. 이는 LINQ (= 언어 통합 쿼리 )가 컬렉션의 쿼리에 사용 되기 때문 입니다. 모든 LINQ 메서드는 기본 컬렉션을 수정하지 않고 새 컬렉션을 반환 합니다 (또는 더 정확한 반복자를 새 컬렉션에 반환). 따라서 예를 들어를 사용 Select하여 기본 컬렉션에 영향을 미치지 않으면 서 새로운 컬렉션을 얻게됩니다.

물론 당신은 할 수 함께 할 ForEach(안 그런데 LINQ,하지만 확장에이다 List<T>). 그러나 이것은 문자 그대로foreach 어쨌든 사용 하지만 람다 표현과 함께 사용 됩니다. 이 외에도에서 모든 LINQ 방법은 내부적으로 사용하여 수집 등을 반복 할 foreach또는 for단순히 클라이언트에서 숨 깁니다 그러나. 나는 이것을 더 읽기 쉽고 유지 보수 할 수 있다고 생각하지 않습니다 (람다 식을 포함하는 메소드를 디버깅하는 동안 코드 편집을 생각하십시오).

LINQ를 사용 하여 컬렉션의 항목 을 수정 해서는 안됩니다 . 더 좋은 방법은 질문에 이미 제공 한 솔루션입니다. 클래식 루프를 사용하면 컬렉션을 쉽게 반복하고 항목을 업데이트 할 수 있습니다. 실제로 의존하는 모든 솔루션 List.ForEach은 다르지 않지만 제 관점에서 읽기가 훨씬 어렵습니다.

따라서 컬렉션의 요소 를 업데이트 하려는 경우 LINQ를 사용하지 않아야합니다 .


3
주제 외 : 동의합니다. LINQ의 많은 사례가 남용되고 있습니다. "고성능 LINQ 체인"을 요청하는 사람들의 예, 단일 루프 등으로 수행 할 수있는 작업 수행 등이 있습니다. LINQ를 사용하지 않는 것이 좋습니다. 나에게 깊이 뿌리 내리고 일반적으로 사용하지 않습니다. LINQ 체인을 사용하여 단일 작업을 수행하는 사람들이 있습니다. LINQ 명령을 사용할 때마다 for"언더 후드"아래에 다른 루프를 만들고 있다는 사실을 알지 못합니다 . 나는 표준 코딩을 대체하지 않고 간단한 작업을 수행하는 덜 장황한 방법을 만드는 것이 합성 설탕이라고 생각합니다.
ForeverZer0

6

나는 이것에 대해 몇 가지 변형을 시도했으며,이 사람의 해결책으로 계속 돌아갑니다.

http://www.hookedonlinq.com/UpdateOperator.ashx

다시, 이것은 다른 누군가의 솔루션입니다. 그러나 코드를 작은 라이브러리로 컴파일하고 상당히 정기적으로 사용합니다.

앞으로 그의 사이트 (블로그)가 더 이상 존재하지 않을 가능성을 높이기 위해 그의 코드를 여기에 붙여 넣을 것입니다. "필요한 답변이 여기에 있습니다", 클릭 및 데드 URL이라는 게시물을 보는 것보다 나쁘지 않습니다.

    public static class UpdateExtensions {

    public delegate void Func<TArg0>(TArg0 element);

    /// <summary>
    /// Executes an Update statement block on all elements in an IEnumerable<T> sequence.
    /// </summary>
    /// <typeparam name="TSource">The source element type.</typeparam>
    /// <param name="source">The source sequence.</param>
    /// <param name="update">The update statement to execute for each element.</param>
    /// <returns>The numer of records affected.</returns>
    public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> update)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (update == null) throw new ArgumentNullException("update");
        if (typeof(TSource).IsValueType)
            throw new NotSupportedException("value type elements are not supported by update.");

        int count = 0;
        foreach (TSource element in source)
        {
            update(element);
            count++;
        }
        return count;
    }
}



int count = drawingObjects
        .Where(d => d.IsSelected && d.Color == Colors.Blue)
        .Update(e => { e.Color = Color.Red; e.Selected = false; } );

1
Action<TSource>추가 대리인을 만드는 대신 대신 사용할 수 있습니다 . 하지만 글을 쓰는 시점에는 사용할 수 없었을 것입니다.
Frank J

예, 그것은 당시의 구식 DotNet이었습니다. 좋은 의견 Frank.
granadaCoder 2016 년

URL이 죽었습니다! (이 도메인 이름이 만료되었습니다) 여기서 코드를 복사했습니다. #patOnShoulder
granadaCoder

1
값 유형을 확인하는 것이 합리적이지만 where T: struct컴파일 타임에 이것을 잡기 위해 제약 조건을 사용하는 것이 좋습니다 .
Groo


3

나는 그것을 도울 수있는 확장 방법을 썼다.

namespace System.Linq
{
    /// <summary>
    /// Class to hold extension methods to Linq.
    /// </summary>
    public static class LinqExtensions
    {
        /// <summary>
        /// Changes all elements of IEnumerable by the change function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="change">The way you want to change the stuff</param>
        /// <returns>An IEnumerable with all changes applied</returns>
        public static IEnumerable<T> Change<T>(this IEnumerable<T> enumerable, Func<T, T> change  )
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(change, "change");

            foreach (var item in enumerable)
            {
                yield return change(item);
            }
        }

        /// <summary>
        /// Changes all elements of IEnumerable by the change function, that fullfill the where function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="change">The way you want to change the stuff</param>
        /// <param name="where">The function to check where changes should be made</param>
        /// <returns>
        /// An IEnumerable with all changes applied
        /// </returns>
        public static IEnumerable<T> ChangeWhere<T>(this IEnumerable<T> enumerable, 
                                                    Func<T, T> change,
                                                    Func<T, bool> @where)
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(change, "change");
            ArgumentCheck.IsNullorWhiteSpace(@where, "where");

            foreach (var item in enumerable)
            {
                if (@where(item))
                {
                    yield return change(item);
                }
                else
                {
                    yield return item;
                }
            }
        }

        /// <summary>
        /// Changes all elements of IEnumerable by the change function that do not fullfill the except function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="change">The way you want to change the stuff</param>
        /// <param name="where">The function to check where changes should not be made</param>
        /// <returns>
        /// An IEnumerable with all changes applied
        /// </returns>
        public static IEnumerable<T> ChangeExcept<T>(this IEnumerable<T> enumerable,
                                                     Func<T, T> change,
                                                     Func<T, bool> @where)
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(change, "change");
            ArgumentCheck.IsNullorWhiteSpace(@where, "where");

            foreach (var item in enumerable)
            {
                if (!@where(item))
                {
                    yield return change(item);
                }
                else
                {
                    yield return item;
                }
            }
        }

        /// <summary>
        /// Update all elements of IEnumerable by the update function (only works with reference types)
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="update">The way you want to change the stuff</param>
        /// <returns>
        /// The same enumerable you passed in
        /// </returns>
        public static IEnumerable<T> Update<T>(this IEnumerable<T> enumerable,
                                               Action<T> update) where T : class
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(update, "update");
            foreach (var item in enumerable)
            {
                update(item);
            }
            return enumerable;
        }

        /// <summary>
        /// Update all elements of IEnumerable by the update function (only works with reference types)
        /// where the where function returns true
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="update">The way you want to change the stuff</param>
        /// <param name="where">The function to check where updates should be made</param>
        /// <returns>
        /// The same enumerable you passed in
        /// </returns>
        public static IEnumerable<T> UpdateWhere<T>(this IEnumerable<T> enumerable,
                                               Action<T> update, Func<T, bool> where) where T : class
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(update, "update");
            foreach (var item in enumerable)
            {
                if (where(item))
                {
                    update(item);
                }
            }
            return enumerable;
        }

        /// <summary>
        /// Update all elements of IEnumerable by the update function (only works with reference types)
        /// Except the elements from the where function
        /// </summary>
        /// <param name="enumerable">The enumerable where you want to change stuff</param>
        /// <param name="update">The way you want to change the stuff</param>
        /// <param name="where">The function to check where changes should not be made</param>
        /// <returns>
        /// The same enumerable you passed in
        /// </returns>
        public static IEnumerable<T> UpdateExcept<T>(this IEnumerable<T> enumerable,
                                               Action<T> update, Func<T, bool> where) where T : class
        {
            ArgumentCheck.IsNullorWhiteSpace(enumerable, "enumerable");
            ArgumentCheck.IsNullorWhiteSpace(update, "update");

            foreach (var item in enumerable)
            {
                if (!where(item))
                {
                    update(item);
                }
            }
            return enumerable;
        }
    }
}

나는 이것을 다음과 같이 사용하고있다 :

        List<int> exampleList = new List<int>()
            {
                1, 2 , 3
            };

        //2 , 3 , 4
        var updated1 = exampleList.Change(x => x + 1);

        //10, 2, 3
        var updated2 = exampleList
            .ChangeWhere(   changeItem => changeItem * 10,          // change you want to make
                            conditionItem => conditionItem < 2);    // where you want to make the change

        //1, 0, 0
        var updated3 = exampleList
            .ChangeExcept(changeItem => 0,                          //Change elements to 0
                          conditionItem => conditionItem == 1);     //everywhere but where element is 1

인수 점검을 참조하십시오.

/// <summary>
/// Class for doing argument checks
/// </summary>
public static class ArgumentCheck
{


    /// <summary>
    /// Checks if a value is string or any other object if it is string
    /// it checks for nullorwhitespace otherwhise it checks for null only
    /// </summary>
    /// <typeparam name="T">Type of the item you want to check</typeparam>
    /// <param name="item">The item you want to check</param>
    /// <param name="nameOfTheArgument">Name of the argument</param>
    public static void IsNullorWhiteSpace<T>(T item, string nameOfTheArgument = "")
    {

        Type type = typeof(T);
        if (type == typeof(string) ||
            type == typeof(String))
        {
            if (string.IsNullOrWhiteSpace(item as string))
            {
                throw new ArgumentException(nameOfTheArgument + " is null or Whitespace");
            }
        }
        else
        {
            if (item == null)
            {
                throw new ArgumentException(nameOfTheArgument + " is null");
            }
        }

    }
}

2

내 두 동전 :-

 collection.Count(v => (v.PropertyToUpdate = newValue) == null);

7
생각처럼 I,하지만 정말 코드가 무엇을하고 있는지 명확하지가
lomaxx

2

LINQ를 사용하여 컬렉션을 배열로 변환 한 다음 Array.ForEach ()를 호출 할 수 있습니다.

Array.ForEach(MyCollection.ToArray(), item=>item.DoSomeStuff());

분명히 이것은 구조체 모음이나 정수 또는 문자열과 같은 내장 유형에서는 작동하지 않습니다.


1

내가 사용하는 확장 방법은 다음과 같습니다.

    /// <summary>
    /// Executes an Update statement block on all elements in an  IEnumerable of T
    /// sequence.
    /// </summary>
    /// <typeparam name="TSource">The source element type.</typeparam>
    /// <param name="source">The source sequence.</param>
    /// <param name="action">The action method to execute for each element.</param>
    /// <returns>The number of records affected.</returns>
    public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> action)
    {
        if (source == null) throw new ArgumentNullException("source");
        if (action == null) throw new ArgumentNullException("action");
        if (typeof (TSource).IsValueType)
            throw new NotSupportedException("value type elements are not supported by update.");

        var count = 0;
        foreach (var element in source)
        {
            action(element);
            count++;
        }
        return count;
    }

"값 유형 요소가 업데이트에서 지원되지 않는 이유"?? 아무것도 방해하지 않습니다!
abatishchev

그것은 내가 작업했던 프로젝트에만 해당됩니다. 나는 그것이 대부분의 경우 중요하지 않다고 생각합니다. 최근에 나는 그것을 재 작업하고 이름을 Run (...)으로 바꾸고 값 유형을 제거한 다음 void를 반환하고 카운트 코드를 삭제하도록 변경했습니다.
Bill Forney

그것은 List<T>.ForEach또한 무엇을 하는가에 대한 것이지만 모두를위한 것 IEnumerable입니다.
HimBromBeere

이것을 되돌아 보면 foreach 루프를 사용한다고 말할 수 있습니다. 이와 같은 것을 사용하는 유일한 이점은 메소드를 함께 연결하고 함수에서 열거 가능 항목을 리턴하여 조치를 실행 한 후에 체인을 계속하려는 경우입니다. 그렇지 않으면 이것은 이점이없는 추가 메소드 호출 일뿐입니다.
Bill Forney

0

쿼리 내에서 값을 변경하여 함수를 작성할 수 있다고 가정합니다.

void DoStuff()
{
    Func<string, Foo, bool> test = (y, x) => { x.Bar = y; return true; };
    List<Foo> mylist = new List<Foo>();
    var v = from x in mylist
            where test("value", x)
            select x;
}

class Foo
{
    string Bar { get; set; }
}

그러나 이것이 당신이 의미하는 바라면 순결하지 않습니다.


이것은 v를 열거 할 무언가가 필요할 때 올바른 방향으로 가고 있습니다. 그렇지 않으면 아무것도하지 않습니다.
AnthonyWJones


-3

아래와 같은 데이터가 있다고 가정 해 봅시다.

var items = new List<string>({"123", "456", "789"});
// Like 123 value get updated to 123ABC ..

목록을 수정하고 목록의 기존 값을 수정 된 값으로 바꾸려면 먼저 비어있는 새 목록을 만든 다음 각 목록 항목에서 수정 방법을 호출하여 데이터 목록을 반복합니다.

var modifiedItemsList = new List<string>();

items.ForEach(i => {
  var modifiedValue = ModifyingMethod(i);
  modifiedItemsList.Add(items.AsEnumerable().Where(w => w == i).Select(x => modifiedValue).ToList().FirstOrDefault()?.ToString()) 
});
// assign back the modified list
items = modifiedItemsList;

2
왜 O (n) 런타임에서 실행할 수있는 것을 O (n ^ 2)에서 실행하거나 더 나쁜 것으로 만들겠습니까? 나는 linq의 특정 기능이 어떻게 작동하는지 알지 못하지만 이것이 n 문제에 대한 최소한의 해결책이라고 볼 수 있습니다 .
Fallenreaper
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.