Bir koleksiyondaki tüm nesneleri LINQ kullanarak güncelleme


500

LINQ kullanarak aşağıdakileri yapmanın bir yolu var mı?

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

Açıklığa kavuşturmak için, bir koleksiyondaki her nesne arasında yineleme yapmak ve daha sonra her nesne üzerindeki bir özelliği güncellemek istiyorum.

Benim kullanım durumum, bir blog yayınında bir sürü yorumum var ve bir blog yayınındaki her yorumu tekrarlamak ve blog yayınındaki tarih saatini +10 saat olarak ayarlamak istiyorum. SQL'de yapabilirdim, ancak iş katmanında tutmak istiyorum.


14
İlginç soru. Şahsen yukarıda nasıl bulduğunuzu tercih ediyorum - neler olduğunu çok daha net!
noelicus

8
Buraya aynı soruya bir cevap aramaya geldim ve gelecekteki geliştiricilerin bunu OP'de yaptığınız gibi yapmasının daha kolay, daha az kod ve anlamanın daha kolay olduğuna karar verdim.
Casey Crookston

4
Neden LINQ ile yapmak istersiniz?
Hesap Makinesi

13
Bu soru yanlış bir şey soruyor, tek doğru cevap: veri kaynağını değiştirmek için LINQ kullanmayın
Tim Schmelter

Bu soruyu konu dışı olarak kapatmak için oy kullanıyorum çünkü bu sorunun hemen hemen tüm yanıtları yeni programcıların LINQ anlayışına aktif olarak zarar veriyor.
Tanveer Badar

Yanıtlar:


842

Bir ForEachuzantı yöntemini kullanabilirsiniz , ancak yalnızca çerçeveyi kullanmak istiyorsanız

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

ToListNedeniyle hemen seçmek değerlendirmek için gerekli olan tembel değerlendirme .


6
Bunu çok iyi bir çözüm olarak gördüm çünkü ... uzantı yöntemini sevmemin tek nedeni, tam olarak ne olduğunu anlamayı biraz daha açık hale getirmesidir ... ancak çözümünüz hala oldukça tatlı
lomaxx

9
Koleksiyon bir ObservableCollectionsöz ise, yeni bir liste oluşturmak yerine öğeleri değiştirmek yararlı olabilir.
Cameron MacFarland

7
@desaivv evet bu bir sözdizimi kötüye kullanımı biraz, bu yüzden Resharper bu konuda sizi uyarıyor.
Cameron MacFarland

46
IMHO, bu basit bir foreach döngüsüne göre çok daha az etkileyici. ToList () kafa karıştırıcıdır, çünkü aksi takdirde ertelenecek olan değerlendirmeyi zorlamaktan başka bir şey için kullanılmaz. Projeksiyon da kafa karıştırıcı çünkü amaçlanan amacı için kullanılmıyor; bunun yerine, koleksiyonun öğeleri üzerinde yineleme yapmak ve güncellenmesi için bir özelliğe erişim izni vermek için kullanılır. Aklımdaki tek soru, foreach döngüsünün Parallel.ForEach kullanarak paralellikten faydalanıp faydalanamayacağıdır, ancak bu farklı bir sorudur.
Philippe

37
Bu cevap en kötü uygulamadır. Bunu asla yapma.
Eric Lippert

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

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

@CameronMacFarland: Tabii ki yapılar değişmez olduğu için olmayacak. Ama gerçekten istiyorsanız, bunu yapabilirsiniz:collection.ToList().ForEach(c => { collection[collection.IndexOf(c)] = new <struct type>() { <propertyToSet> = value, <propertyToRetain> = c.Property2Retain }; });
Ε Г И І И О

11
Bu, Cameron MacFarland'ın yeni bir liste oluşturmak yerine listeyi güncelleştirme cevabına göre avantajı var.
Simon Tewsi

7
Vay, bu cevap gerçekten kullanışlı değil. Sadece bir döngü kullanabilmek için yeni bir koleksiyon oluşturma
Tim Schmelter

@SimonTewsi Bir nesne koleksiyonu olduğu için liste yine de güncellenmelidir. Koleksiyon yeni olacak, ancak koleksiyondaki nesneler aynı olacak.
Chris

70

Bunu yapıyorum

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

Bunu yapmanın en temiz yolu olduğunu düşünüyorum.
wcm

31
Bu yaklaşım kesinlikle işe yarıyor ancak All()uzatma yönteminin amacını ihlal ediyor ve başka biri kodu okuduğunda karışıklığa yol açıyor.
Tom Baxter

Bu döngü daha iyidir. Her döngüyü kullanmak yerine Tümünü Kullanmak
UJS

2
All () için ne kullandığına dair biraz yanıltıcı olsa bile, gereksiz yere ToList () çağrılmasını tercih edin.
iupchris10

1
Böyle bir koleksiyon kullanıyorsanız List<>, ForEach()yöntem bunu başarmak için çok daha az şifreli bir yoldur. exForEach(c => { c.needsChange = value; })
Dan Is Fiddling Tarafından Firelight

27

Aslında istediğimi yapacak bir uzatma yöntemi buldum

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

4
güzel :) Lomaxx, belki bir örnek eklemek böylece peeps 'eylem' (Boom tish!) içinde görebilirsiniz.
Pure.Krome

2
Eğer gerçekten foreach-her döngüden (hangi nedenle olursa olsun) kaçınmak istiyorsanız, bu tek faydalı yaklaşımdır .
Tim Schmelter

@Rango hala foreachkod kendisini foreachdöngü içerdiği için kaçınmak değil
GoldBishop

@GoldBishop, yöntem döngüyü gizler.
Tim Schmelter

1
Bağlantı koptu, artık şu adreste bulunabilir: codewrecks.com/blog/index.php/2008/08/13/… . Ayrıca stackoverflow.com/questions/200574 adresine bağlantı veren bir blog yorumu da vardır . Buna karşılık, en üstteki soru yorumu blogs.msdn.microsoft.com/ericlippert/2009/05/18/… ' a bağlanır . Belki de cevap MSDN'yi kullanarak daha basit bir şekilde yeniden yazılır (isterseniz ilk bağlantıyı yine de kredilendirebilirsiniz). Sidenote: Rust benzer özelliklere sahip ve sonunda eşdeğer işlevi verdi ve ekledi: stackoverflow.com/a/50224248/799204
sourcejedi

15

kullanın:

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

Bunun LINQ'yu gereğinden fazla kullanıp kullanmadığından emin değilim, ancak belirli bir durum için listedeki belirli bir öğeyi güncellemek isterken benim için çalıştı.


7

Bunu yapmak için yerleşik bir uzantı yöntemi yoktur. Bir tanesini tanımlamak oldukça basit olsa da. Gönderinin alt kısmında Iterate adı verilen bir yöntem var. Bu şekilde kullanılabilir

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

Yineleme Kaynağı

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

Yineleme gerekli midir, Say, Toplam, Ort veya skaler değer döndüren mevcut diğer uzantı yöntemlerinde yanlış olan nedir?
AnthonyWJones

2
Bu istediğim oldukça yakın ama biraz .. dahil. Gönderdiğim blog yazısı benzer bir uygulamaya sahip ancak daha az kod satırı içeriyor.
lomaxx

1
IterateHelper aşırıya kaçmış gibi görünüyor. Bir indeks almayan aşırı yük, çok daha fazla iş çıkarır (geri çağrıyı indeks alan lambda'ya dönüştür, asla kullanılmayan bir sayıyı tut). Yeniden kullanımını anlıyorum, ancak yine de bir forloop kullanmak için bir çözüm, bu yüzden verimli olmalı.
Cameron MacFarland

2
@Cameron, IterateHelper 2 amaca hizmet ediyor. 1) Tekli uygulama ve 2) ArgumentNullException'ın çağrıya karşılık kullanıma karşı atılmasına izin verir. C # yineleyicileri, yardımcı, yineleme sırasında bir özel durumun garip davranışını önleyerek, yürütülür.
JaredPar

2
@JaredPar: Bir yineleyici kullanmamanız dışında. Verim beyanı yok.
Cameron MacFarland

7

Özellikle bir LINQ çözümü istedi ve bu soru oldukça eski olmasına rağmen ben LINQ olmayan bir çözüm gönderin. Bunun nedeni , koleksiyonlardaki sorgular için LINQ (= dile tümleşik sorgu ) kullanılmasıdır. Tüm LINQ yöntemleri temel alınan koleksiyonu değiştirmez, sadece yeni bir tane döndürür (veya yeni bir koleksiyona daha kesin bir yineleyici). Böylece ne yaparsanız yapın örneğinSelect , alttaki koleksiyonu etkilemez, sadece yeni bir koleksiyon alırsınız.

Tabii ki olabilir bir ile yapmak ForEach(değil bu arada LINQ, ancak bir uzantısı üzerinde olan List<T>). Ancak bu kelimenin tam anlamıyla , foreachlambda ifadesi ile kullanılıyor. Bunun dışında her LINQ yöntemi, koleksiyonunuzu dahili olarak yineleyerek foreachveya kullanarak for, ancak istemciden gizler. Bu daha okunabilir ne de bakımı yapılabilir (lambda ifadeleri içeren bir yöntemde hata ayıklama sırasında kodunuzu düzenlemeyi düşünün).

Bunu söyledikten sonra koleksiyonunuzdaki öğeleri değiştirmek için LINQ kullanılmamalıdır . Daha iyi bir yol, sorunuzda zaten sağladığınız çözümdür. Klasik bir döngü ile koleksiyonunuzu kolayca tekrarlayabilir ve öğelerini güncelleyebilirsiniz. Aslında tüm bu çözümlere dayanmak List.ForEachfarklı değil, ama benim bakış açımdan okumak çok daha zor.

Bu nedenle , koleksiyonunuzun öğelerini güncellemek istediğiniz durumlarda LINQ kullanmamalısınız .


3
Konu dışı: Katılıyorum ve sooooooo birçok LINQ örneği istismar ediliyor, "yüksek performanslı LINQ zincirleri" isteyen insanların örnekleri, tek bir döngü ile başarılabilecek şeyleri yapmak için, vb. bana çok yerleşmişti ve tipik olarak kullanmıyorum. Tek bir eylem gerçekleştirmek için LINQ zincirlerini kullanan insanları görüyorum, hemen hemen her LINQ komutu kullanıldığında for"başlık altında" başka bir döngü oluşturduğunuzu fark etmiyorsunuz . Standart kodlamanın yerini almamak için basit görevleri yerine getirmenin daha az ayrıntılı yollarını yaratmanın sintatik şeker olduğunu hissediyorum.
ForeverZer0

6

Bu konuda birkaç varyasyon denedim ve bu adamın çözümüne geri dönüyorum.

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

Yine, bu başka birinin çözümü. Ama kodu küçük bir kütüphaneye derledim ve oldukça düzenli kullanıyorum.

Kodunu buraya yapıştıracağım, çünkü sitesinin (blog) gelecekte bir noktada var olma şansı yok. ("İhtiyacınız olan tam yanıt", Tıklama ve Ölü URL) yazan bir yayını görmekten daha kötü bir şey yoktur.)

    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>Ek temsilci oluşturmak yerine kullanabilirsiniz . Bununla birlikte, bu yazı yazılırken mevcut olmayabilir.
Frank J

Evet, o zaman nokta DotNet eski okuluydu. İyi yorum Frank.
granadaCoder

URL öldü! (Bu Alan Adının Süresi Doldu) İyi bir şey kodu buraya kopyaladım! #patOnShoulder
granadaCoder

1
Değer türünü kontrol etmek mantıklıdır, ancak belki de bir kısıtlama kullanmak, yani where T: structbunu derleme zamanında yakalamak daha iyi olacaktır .
Groo


3

Bu konuda bana yardımcı olacak bazı uzatma yöntemleri yazdım.

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

Bu şekilde kullanıyorum:

        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

Argüman kontrolüne referans için:

/// <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

Benim 2 peni: -

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

7
Düşünmeyi seviyorum, ancak kodun ne yaptığını gerçekten net değil
lomaxx

2

Koleksiyonunuzu bir diziye dönüştürmek ve ardından Array.ForEach () öğesini çağırmak için LINQ kullanabilirsiniz:

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

Açıkçası bu, yapı koleksiyonları veya tamsayılar veya dizeler gibi dahili tiplerle çalışmayacaktır.


1

İşte kullandığım uzantı yöntemi ...

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

Neden "değer türü öğeleri güncelleştirme tarafından desteklenmiyor" ?? Hiçbir şey buna engel olmaz!
abatishchev

Üzerinde çalıştığım projeye özgüdür. Sanırım çoğu durumda önemli değil. Son zamanlarda bunu yeniden çalıştım ve yeniden adlandırdım Run (...), değer türü şey kaldırıldı ve geçersiz dönmek için değiştirdi ve sayım kodu düştü.
Bill Forney

Bu da aşağı yukarı List<T>.ForEachaynı şeyi yapıyor, ama sadece herkes için IEnumerable.
HimBromBeere

Şimdi buna baktığımda, sadece bir foreach döngüsü kullanmayı söyleyebilirim. Bunun gibi bir şey kullanmanın tek yararı, yöntemleri birlikte zincirlemek ve eylemi gerçekleştirdikten sonra zinciri devam ettirmek için numaralandırmayı işlevden döndürmek istiyorsanız. Aksi takdirde, bu sadece fayda için ekstra bir yöntem çağrısıdır.
Bill Forney

0

Bir sorgu içindeki değerleri değiştirmek istediğinizi varsayalım.

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

Ama demek istediğin buysa emin değilim.


Bu bir şekilde doğru yönde gidiyor v numaralandırma için bir şey gerektirir, aksi takdirde hiçbir şey yapmaz.
AnthonyWJones


-3

Aşağıdaki gibi verilerimiz olduğunu varsayalım,

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

ve listeyi değiştirmek ve listenin mevcut değerlerini değiştirilmiş değerlerle değiştirmek istiyorsak, önce yeni bir boş liste oluşturun, ardından her bir liste öğesinde değiştirme yöntemini çağırarak veri listesinde dolaşın,

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
Neden O (n) çalışma zamanında çalıştırılabilecek bir şeyi O (n ^ 2) veya daha kötüsü yapasınız ki? Linq özellikleri nasıl çalıştığından habersiz ama bu en azından bir n sorunu için bir ^ 2 çözüm olduğunu görebilirsiniz .
Fallenreaper
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.