Soru c # nesne yapıcısı içinde uyumsuzluk yöntemini başlat - kötü uygulama?


benzer bir nesne kurucusunda bazı kod var

delegate DataSet MyInvoker;

public MyObject(Param1 p1)
{
    // property sets here
    // ...

    BeginMyAsyncMethod();
}

public void BeginMyAsyncMethod() 
{
    // set some properties
    // ...

    MyInvoker inv = new MyInvoker(SomeBeginMethod);
    inv.BeginInvoke(new AsyncCallback(SomeEndMethod), null);
}

Benim sorularım:

  1. Bu genellikle kötü uygulama olarak mı görülür?
  2. Kullanıcının asenkron eylemi gerçekleştirmesi için arayacağı bir başlangıç ​​yöntemi tanımlamak daha iyi (veya iyi) bir uygulama mıdır?

Bu Cevap Bana, kullanıcıya doğru bir inşayı değil, kurucudaki async yöntemlerini başlatma hakkında konuşmamı sağladığım halde, kullanıcıya bırakmanın kötü bir uygulama olduğunu gösterir.


25
2017-08-31 17:49


Menşei


Evet, potansiyel olarak beklenmedik davranışlar getiriyorsunuz. Nesneler inşa edilmeli ve istisnalar ve beklenmedik davranışlardan arınmış olmalıdır. Nesne oluşturulduktan ve kullanıcı onu kullanmaya çalıştıktan sonra async eylemleri devam ediyorsa ... - Dustin Davis
Bu iş parçacığı güvenli değildir, bu yüzden en iyi uygulama olmaz. BeginMyAsyncMethod çalışırken, inv nesnesi başka bir iş parçacığı tarafından okunabilir. Böylece bir iş parçacığının okuduğu ve bir iş parçacığının yazdığı bir çakışma durumunda veya diğer tehlikelerden herhangi biri: en.wikipedia.org/wiki/Hazard_(computer_architecture) - Automatico
Buradaki cevaplar korkunç (JNixon dayanılmaz). Herkes temelde "Bunu neden yapmak isterdiniz ?! Kötü bir uygulama!" Diyor. İşte bu yüzden bunu yapmak istersiniz: .NET 4.5'te HERHANGİ BİR SAYI beklemeden (IO, internet, bir çok iletişim kutusu, vb) yapamazsınız ve genellikle bu şeyler yapıcıya yüklenir. Bu iyi bir soru ve cevaplar kötü. - micahhoover
@micahhoover Bence bu nokta. Yapıcınız olmamalı iş nesneyi başlatmadan başka bir şey. Bunun bir HttpClient'i bir istekte bulunmakla karşılaştırması arasındaki farkın olacağını düşünürdüm. - Ryan Gates


Cevaplar:


Bu biraz farklı bir yaklaşımla kolayca gerçekleştirilebilir. Tüm gerçeklikte, bu her zaman olur, değil mi? İşte size aptalca bir şey yapmadan bir seçenek sunmak için basit bir çözüm:

public class MyResource
{
    // do this instead of a constructor
    public async Task<MyResource> StartAsync()
    {
        await Task.Delay(1);
        return this;
    }
}

public class MyControl
{
    public MyResource Resource { get; set; }
    async void Button_Click(object s, EventArgs e)
    {
        // call start as if it is a constructor
        this.Resource = await new MyResource().StartAsync();
    }
}

22
2017-07-27 22:19



Bu, tüm ViewModel'lerle kullandığım model - Jerry Nixon - MSFT
Söz konusu kaynak yapıcı bağımlılığı enjeksiyonu yoluyla size verildiyse bunu nasıl başarabilirsiniz? StartAsync() Bu yöntem, aynı problemle sonuçlanan farklı bir nesnenin yapıcısından çağrılabilir. - Nathan Friend
@NathanFriend bir fabrika enjekte etti - Meirion Hughes


Genellikle, kurucunuzda nesne örneğini oluşturmayla doğrudan ilgili olmayan bir şey yapmak genellikle iyi bir fikir değildir. Örneğin, eğer amacını bilmiyorsam MyObject sınıf, yeni bir örnek oluşturduğumda eşzamansız bir süreç ortaya çıktığını bilmiyor olabilirim. Bu genellikle kötü bir uygulamadır.

Neredeyse söylediğiniz gibi geliyor; hey, bu nesneyi yarat, ve bu async süreci bittiğinde sadece kullanılabilir olacak; Bu karşı sezgisel.

Böyle bir şey yapmak istiyorsanız, bir fabrika modeline giderek daha iyi hizmet vereceğinizi düşünürdüm; bir fabrikayı böyle çağırırsınız ve nesneyi oluşturarak sizin için yöntemi çağırır:

 var instance = MyObjectBuilder.CreateInstance();

 // Internally, this does
 //    var x = new MyObject();
 //    x.Initilizatize();
 //    return x;

Nesneniz başlatılıncaya kadar kullanılabilir olmayacaksa, hazır olup olmadığını kontrol etmek için muhtemelen bir özellik sergilemeniz gerekir:

 instance.WaitForReady(); // blocking version
 if(instance.IsReady) // non blocking check

12
2017-08-31 17:57





Evet, potansiyel olarak beklenmedik davranışlar getiriyorsunuz. Nesneler inşa edilmeli ve istisnalar ve beklenmedik davranışlardan arınmış olmalıdır. Nesne oluşturulduktan ve kullanıcı onu kullanmaya çalıştıktan sonra async eylemleri devam ediyorsa ...

Ayrıca, async yöntemi hala çalışıyorsa ve kullanıcı nesneyi yok etmeye ne zaman karar verirse?

Güzel bir okuma: http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321545613/ref=sr_1_1?s=books&ie=UTF8&qid=1314813265&sr=1-1

Eşzamansız yönteminiz uzun süren bir işlem olduğundan, uyumsuz olması gerekiyorsa, nesne tarafından çekilmediği zaman kullanıcı tarafından çağrılan kendi yöntemine taşınması gerekir.

Ayrıca kullanıcı, async yöntemi yapılmadan önce onu yok etmeye karar verirse, bir bellek sızıntısına sahip olabileceğiniz anlamına gelen nesneye bir referans tutma konusuna da sahip olursunuz.

Eğer bu başlangıç ​​için yapılması gerekiyorsa, bir fabrika veya bir kurucu kullanılarak nesne oluşturulmalıdır.


8
2017-08-31 17:53



Kullanıcı, nesneyi yok etmeye karar veremez - sadece varlığını unutur ;-) Eğer bir nesneyi zaten varsa, o zaman bunun, “temizlenmiş” olması gereken başka herhangi bir nesneden farklı olmayacak şekilde IDisposable uygulayacağını düşünün. Ayrıca, BeginAsyncX neden bir istisna atardı? (Sonuca katılmıyorum ama ...)
@pst İstersen ister istemezsin. İşte bu nokta. Yöntemin ne olduğuna bağlı. Ancak, kaynak gerektiren, potansiyel olarak hata yapabilecek ve nesnenin durumunu değiştirmeyecek bir şey yapmamalıdır. - Dustin Davis
O zaman nasıl bir farklı Timer?
Katılmıyorum. Doğru bir şekilde kodlanmışsa, UI'nizin kullanıcı performansını performansı artırırken, arka taraftaki verileri hala getirebilirsiniz. Kullanıcı nesneyi zamanından önce yok ettiğinde, iş parçacığınızı doğru bir şekilde imha etmeniz gerekir. Gönderiyi buradan gör. tsells.wordpress.com/2011/03/31/... - tsells
@, doğru bir şekilde yapılıp yapılamayacağına dair bir soru değil, ancak en iyi uygulamalar bağlamında kötü bir uygulama ve cevap evet ise, bu kötü bir uygulamadır. Arabirim yöntemlerinin UI'ye sağladığı yararlarla ilgili bir soru değil. Eğer bu şekilde yapılması gerekiyorsa, bir yapıcıda bunu yapmamak için bir fabrika kullanılmalıdır. - Dustin Davis


Bir kurucuda, örneğin tam olarak oluşturulmadan önce başka bir iş parçacığı örneğine geri çağırabilecek herhangi bir şeyi başlatmak kesinlikle kötü bir fikirdir. Son satırı olsa bile sizin Kurucu, alt sınıf yapıcı kodun, alt sınıf yapıcı kodu taban sınıf yapıcı kodundan sonra çalıştığı için çalışmayı bitirmeden önce çağrılabilir. Sınıfınız bugün mühürlenmiş olsa bile, gelecekte açığa çıkarılabilir ve ileride bir alt sınıf eklenirse bu tür bir sorunun izlenmesi büyük olasılıkla çok pahalı olacaktır.

Temel olarak, eğer heisenbug avına son vermek istemezsen, asla bir kurucudan böyle bir şeyi yapmazsın. Bunun yerine, 2. soruda bahsettiğiniz gibi bir "başlangıç" yöntemi ekleyin.


5
2017-08-31 18:57





Katılıyorum, kötü fikir. Bir Initialize yöntemi ekleyin. Yeni nesneyi döndüren ve Initialize yöntemini yürüten statik bir yöntem de ekleyebilirsiniz. Bu şekilde kurucuyu özel olarak da tutabilirsiniz.

public class XXX
{
    private XXX()
    {
    }

    private void DoMyWeirdThingsAsynchronously()
    {
        ....
    }

    public static XXX PerformSomethingStrange()
    {
        XXX result = new XXX();
        result.DoMyWeirdThingsAsynchronously();
        return result;
    }
}

5
2017-08-31 20:28



Bu öneriyi gerçekten çok beğendim. Temel olarak Tejs ile aynıdır, ancak özel kurucu (lar) da dahil edilerek biraz daha nettir. Ayrıca, kolayca cevaplayabildiği (2011'de cevap verildi) anahtar kelimeler / anahtar kelimeler kullanılmasa da, JNixon'lardan daha iyi bir tasarım seçeneği olduğunu düşünüyorum. Çünkü bu, sahne arkasındaki async başlatma işleminin sorumluluğunu daha çok kapsıyor. arayanın 'bunu' bilmesini (örn. bir örnek oluşturup sonra bir async başlatma yöntemini çağırmasını) gerektirmektedir. - mdisibio


Şahsen ben böyle bir kodu bir kurucuya koymaktan kaçınırdım. Eşzamansız çalışmayı başlatmak için belirli bir yöntem sağlamak daha iyi olurdu. Bir yapıcıdan (doğrulama istisnası dışında) istisnalar atmak kötü bir fikirdir.


0
2017-08-31 17:53



Sonucuna karşı tartıştığımdan değil, ama BeginAsyncX neden bir istisna atar?
@pst neden olmasın? - Dustin Davis