Anonim türleri parametre olarak nasıl iletebilirim?


143

Anonim türleri diğer işlevlere parametre olarak nasıl iletebilirim? Bu örneği düşünün:

var query = from employee in employees select new { Name = employee.Name, Id = employee.Id };
LogEmployees(query);

Buradaki değişkenin querygüçlü türü yoktur. İşlevimi LogEmployeeskabul etmek için nasıl tanımlamalıyım ?

public void LogEmployees (? list)
{
    foreach (? item in list)
    {

    }
}

Başka bir deyişle, ?işaretler yerine ne kullanmalıyım .


1
Veri döndürmek yerine geçiş parametreleriyle ilgilenen daha iyi farklı yinelenen soru: stackoverflow.com/questions/16823658/…
Rob Church

Yanıtlar:


183

Sanırım bu anonim tip için bir sınıf yapmalısın. Bu benim görüşüme göre yapılacak en mantıklı şey olurdu. Ama gerçekten istemiyorsanız, dinamikleri kullanabilirsiniz:

public void LogEmployees (IEnumerable<dynamic> list)
{
    foreach (dynamic item in list)
    {
        string name = item.Name;
        int id = item.Id;
    }
}

Not Bu olduğunu değil kesinlikle yazılı, böylece örneğin, İsim EmployeeName şekilde değiştiren varsa, bir sorun çalışma zamanı kadar var bilemezsiniz.


dynamicKullanım nedeniyle bunu doğru cevap olarak kontrol ettim . Benim için gerçekten kullanışlı geldim. Teşekkürler :)
Saeed Neamati

1
Veri aktarılmaya başladığında, hataları bulmak zor olmamak için normalde daha yapısal bir yolun tercih edilebileceğini kabul etmeliyim. Ancak, bir uzlaşma bulmak istiyorsanız, başka bir yol sadece genel bir Sözlük geçirmektir. C # sözlük başlatıcıları bugünlerde kullanmak için oldukça uygundur.
Jonas

Genel bir uygulama istediğiniz bazı durumlar vardır ve zor türlerden geçmek, muhtemelen kodları şişirmeye başlayan anahtarlama veya fabrika uygulaması anlamına gelir. Gerçekten dinamik bir durumunuz varsa ve aldığınız verilerle ilgilenmek için küçük bir yansımanın sakıncası yoksa, bu mükemmeldir. Cevabınız için teşekkürler @Tim S.
Larry Smith

42

Bunu şu şekilde yapabilirsiniz:

public void LogEmployees<T>(List<T> list) // Or IEnumerable<T> list
{
    foreach (T item in list)
    {

    }
}

... ama her eşya için fazla bir şey yapamazsın. ToString'i arayabilirsiniz, ancak doğrudan Nameve kullanamazsınız Id.


2
Bunun dışında where T : some typeilk satırın sonunda türü daraltmak için kullanabilirsiniz. Bununla birlikte, bu noktada, belirli bir ortak arabirim türünün beklenmesi, bir arabirim beklemek için daha anlamlı olacaktır. :)
CassOnMars

9
@d_r_w: where T : some typeHerhangi bir arabirim uygulamadığı için anonim türlerle kullanamazsınız ...
Jon Skeet

@dlev: Bunu yapamazsınız, foreach, GetEnumerator aracında yinelenen değişkenin kullanılmasını gerektirir ve anonim türler bunu garanti etmez.
CassOnMars

1
@Jon Skeet: iyi bir nokta, beynim bu sabah yeterince güçsüz.
CassOnMars

1
@JonSkeet. Sanırım T anonim bir tür ise özellikleri erişmek / ayarlamak için yansıma kullanabilirsiniz değil mi? Birisi bir "Select * from" deyimi yazıyor ve anonim nesnenizde aynı adlandırılmış özelliklere sorgu sonuç eşlemesinden hangi sütunları tanımlamak için anonim (veya tanımlanmış) sınıf kullanan bir durum düşünüyorum.
C. Tewalt

19

Ne yazık ki, yapmaya çalıştığınız şey imkansız. Kaputun altında, sorgu değişkeni IEnumerableanonim türden olacak şekilde yazılır . Anonim tür adları kullanıcı kodunda gösterilemez, bu nedenle onları bir işleve giriş parametresi yapmanın bir yolu yoktur.

En iyi seçeneğiniz bir tür oluşturmak ve bunu sorgudan dönüş olarak kullanmak ve daha sonra işleve aktarmaktır. Örneğin,

struct Data {
  public string ColumnName; 
}

var query = (from name in some.Table
            select new Data { ColumnName = name });
MethodOp(query);
...
MethodOp(IEnumerable<Data> enumerable);

Bu durumda, yalnızca tek bir alan seçersiniz, bu nedenle alanı doğrudan seçmek daha kolay olabilir. Bu, sorgunun IEnumerablealan türünden biri olarak yazılmasına neden olur . Bu durumda, sütun adı.

var query = (from name in some.Table select name);  // IEnumerable<string>

Benim örneğim bir, ama çoğu zaman daha fazla. Çalışmalar yoluyla cevabınız (ve şimdi oldukça açık). Ama düşünmek için öğle yemeği için bir mola gerekiyordu ;-)
Tony Trembath-Drake


Bir uyarı, uygun bir sınıf oluşturduğunuzda Equalsdavranışı değiştirir. Yani bunu uygulamak zorundasınız. (Bu tutarsızlığı biliyordum ama yine de bir yeniden düzenleme sırasında unutmayı başardım.)
LosManos

11

Parametre türü olmadıkça, anonim bir türü genel olmayan bir işleve geçiremezsiniz object.

public void LogEmployees (object obj)
{
    var list = obj as IEnumerable(); 
    if (list == null)
       return;

    foreach (var item in list)
    {

    }
}

Anonim türler, bir yöntem içinde kısa süreli kullanım için tasarlanmıştır.

MSDN'den - Anonim Türler :

Bir alanı, özelliği, olayı veya yöntemin dönüş türünü anonim bir tür olarak bildiremezsiniz. Benzer şekilde, bir yöntem, özellik, yapıcı veya dizinleyicinin resmi bir parametresini anonim bir türe sahip olarak bildiremezsiniz. Adsız bir türü veya adsız türler içeren bir koleksiyonu bir yönteme bağımsız değişken olarak iletmek için, parametreyi tür nesnesi olarak bildirebilirsiniz . Ancak, bunu yapmak güçlü yazmanın amacını yener.

(benimkini vurgula)


Güncelleme

İstediğinizi başarmak için jenerik ilaçları kullanabilirsiniz:

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {

    }
}

4
Anonim türleri (veya anonim tipteki koleksiyonları) yöntemlere geçiremezseniz, LINQ'nun tamamı başarısız olur. Bu, anonim türün özelliklerini kullanmadan sadece yöntemin tamamen genel olması gerektiğidir.
Jon Skeet

2
re object- or dynamic; p
Marc Gravell

"As" ile yayın yapıyorsanız, listenin boş olup olmadığını kontrol etmelisiniz
Alex

"can"! = "zorunda". Kullanmak object, cevabım gereğince anonim tipte genel bir yöntem yapmakla aynı şey değildir.
Jon Skeet

8

Normalde, bunu jeneriklerle yaparsınız, örneğin:

MapEntToObj<T>(IQueryable<T> query) {...}

Derleyici Taradığınızda çıkarımda bulunmalıdır MapEntToObj(query). Yöntemin içinde ne yapmak istediğinizden tam olarak emin değilim, bu yüzden bunun yararlı olup olmadığını söyleyemem ... sorun şu ki, içinde MapEntToObjhala isim Tveremiyorsunuz - ya da şunları yapabilirsiniz:

  • diğer genel yöntemleri T
  • bir Tşeyler yapmak için yansımayı kullan

ama bunun dışında, isimsiz türleri manipüle etmek oldukça zordur - en azından değişmez oldukları için ;-p

Başka bir hile ( veri çıkarılırken ) aynı zamanda bir seçici geçirmektir - yani:

Foo<TSource, TValue>(IEnumerable<TSource> source,
        Func<TSource,string> name) {
    foreach(TSource item in source) Console.WriteLine(name(item));
}
...
Foo(query, x=>x.Title);

1
Yeni bir şey öğrendim, anonim türlerin değişmez olduğunu bilmiyordum! ;)
Annie Lagang

1
@AnneLagang, onları oluşturduğu için derleyiciye bağlı. VB.NET'te anon tipleri değiştirilebilir.
Marc Gravell


7

Jenerikleri aşağıdaki hile ile kullanabilirsiniz (anonim türe döküm):

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {
        var typedItem = Cast(item, new { Name = "", Id = 0 });
        // now you can use typedItem.Name, etc.
    }
}

static T Cast<T>(object obj, T type)
{
    return (T)obj;
}

6

"dinamik" de bu amaçla kullanılabilir.

var anonymousType = new { Id = 1, Name = "A" };

var anonymousTypes = new[] { new { Id = 1, Name = "A" }, new { Id = 2, Name = "B" };

private void DisplayAnonymousType(dynamic anonymousType)
{
}

private void DisplayAnonymousTypes(IEnumerable<dynamic> anonymousTypes)
{
   foreach (var info in anonymousTypes)
   {

   }
}

1
Bu doğru cevap! Sadece daha fazla aşka ihtiyacı var :)
Korayem

2

Anonim bir tür iletmek yerine, dinamik türden bir Liste iletin:

  1. var dynamicResult = anonymousQueryResult.ToList<dynamic>();
  2. Yöntem imzası: DoSomething(List<dynamic> _dynamicResult)
  3. Çağrı yöntemi: DoSomething(dynamicResult);
  4. yapılır.

Petar Ivanov'a teşekkürler !


0

Sonuçlarınızın belirli bir arayüz uyguladığını biliyorsanız, arayüzü veri türü olarak kullanabilirsiniz:

public void LogEmployees<T>(IEnumerable<T> list)
{
    foreach (T item in list)
    {

    }
}

0

IEnumerable<object>Argüman için tip olarak kullanırım . Ancak kaçınılmaz açık kadro için büyük bir kazanç değil. Şerefe

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.