2012-02-06 18 views
17

Task<T> लौटने वाले एसिंक विधियों में पोस्टकंडिशन जोड़ने का अनुशंसित तरीका क्या है?कोड अनुबंध और असीमितता

मैं निम्नलिखित सुझाव पढ़ा है:

http://social.msdn.microsoft.com/Forums/hu-HU/async/thread/52fc521c-473e-4bb2-a666-6c97a4dd3a39

पोस्ट, तुल्यकालिक के रूप में प्रत्येक विधि को लागू करने का सुझाव यह करार, और फिर एक सरल आवरण के रूप में एक async समकक्ष को लागू करने।

  1. async विधि, सिंक विधि के लिए एक आवरण माना हालांकि, किसी भी वास्तविक कोड अनुबंध के बिना छोड़ दिया और कर सकते हैं इसलिए: दुर्भाग्य से मैं से समस्या का समाधान (शायद अपने ही गलतफहमी के माध्यम से) के रूप में देखते नहीं है जैसा चाहें वैसा करो।
  2. एसिंक्रनाइज़ेशन के लिए प्रतिबद्ध कोडबेस जो सब कुछ के लिए सिंक समकक्षों को लागू करने की संभावना नहीं है। नतीजतन, अन्य विधियों को लागू करने में await एस अन्य एसिंक तरीकों पर लागू होते हैं जिसके परिणामस्वरूप एसिंक होने के लिए मजबूर किया जाता है। ये विधियां आंतरिक रूप से असीमित हैं और आसानी से तुल्यकालिक रूपांतरित नहीं हो सकती हैं। वे बस रैपर नहीं हैं।

यहां तक ​​कि अगर हम कह हम .Result या await के बजाय .Wait() इस्तेमाल कर सकते हैं द्वारा उत्तरार्द्ध बिंदु अवैध (जो वास्तव में कुछ SyncContext रों गतिरोध कर सकता है, और वैसे भी async विधि में फिर से लिखा करना होगा), मैं अभी भी पहले बिंदु के बारे में आश्वस्त हूँ।

क्या कोई वैकल्पिक विचार है, या क्या कुछ ऐसा है जो मुझे कोड-अनुबंध और टीपीएल के बारे में याद आया है?

+1

कोई भी कहा MVPs गलत नहीं मिल सकता है। –

उत्तर

14

मैंने इसे एसिंक टीम को इंगित किया है, जैसा कि अन्य ने किया है। वर्तमान में, अनुबंध और Async (लगभग) पारस्परिक रूप से अनन्य हैं। इसलिए, माइक्रोसॉफ्ट में कम से कम कुछ लोग इस समस्या से अवगत हैं, लेकिन मुझे पता नहीं है कि वे इसके बारे में क्या करने की योजना बना रहे हैं।

मैं सिंक विधियों के लिए रैपर के रूप में async विधियों को लिखने की अनुशंसा नहीं करता हूं। वास्तव में, मैं विपरीत करना होगा।

पूर्व शर्त कार्य कर सकते हैं। मैंने हाल ही में कोशिश नहीं की है; आपको अपनी एसिंक विधि के चारों ओर एक छोटे से आवरण की आवश्यकता हो सकती है जिसमें पूर्व शर्त शामिल है।

पोस्टकंडिशन काफी टूटा हुआ है।

दावा और धारणाएं सामान्य रूप से काम करती हैं, लेकिन स्थिर जांचकर्ता वास्तव में सीमित है क्योंकि पोस्टकंडिशन टूटा हुआ है।

Invariants Async दुनिया में उतना अधिक समझ नहीं लेते हैं, जहां परस्पर राज्य बस रास्ते में आ जाता है। (Async धीरे-धीरे आपको ओओपी से दूर और एक कार्यात्मक शैली की ओर धक्का देता है)।

उम्मीद है कि वीएस vNext में, अनुबंधों को एसिंक-जागरूक पोस्टकंडिशन के साथ अपडेट किया जाएगा, जो स्थिर जांचकर्ता को एसिंक विधियों में दावे के साथ बेहतर काम करने में सक्षम बनाता है।

इस दौरान, आप एक मान लिख कर एक नाटक-postcondition हो सकता है:

// Synchronous version for comparison. 
public static string Reverse(string s) 
{ 
    Contract.Requires(s != null); 
    Contract.Ensures(Contract.Result<string>() != null); 

    return ...; 
} 

// First wrapper takes care of preconditions (synchronously). 
public static Task<string> ReverseAsync(string s) 
{ 
    Contract.Requires(s != null); 

    return ReverseWithPostconditionAsync(s); 
} 

// Second wrapper takes care of postconditions (asynchronously). 
private static async Task<string> ReverseWithPostconditionAsync(string s) 
{ 
    var result = await ReverseImplAsync(s); 

    // Check our "postcondition" 
    Contract.Assume(result != null); 

    return result; 
} 

private static async Task<string> ReverseImplAsync(string s) 
{ 
    return ...; 
} 

कुछ कोड ठेके के उपयोगों के बस नहीं संभव हो रहे हैं -, इंटरफेस या आधार वर्ग के async सदस्यों पर निर्दिष्ट करने postconditions जैसे ।

व्यक्तिगत रूप से, मैंने पूरी तरह से अपने असिनक कोड में अनुबंधों से परहेज किया है, उम्मीद है कि माइक्रोसॉफ्ट कुछ महीनों में इसे ठीक करेगा।

+0

आपने बताया कि आपने आशा की थी कि "माइक्रोसॉफ्ट इसे कुछ महीनों में ठीक करेगा" क्या आपने इसे पोस्ट करते समय स्थिति बदल दी? क्या आप अभी भी एसिंक तरीकों पर अनुबंध से बचते हैं? – julealgon

+2

@ जुलेलगॉन: दुर्भाग्य से, नहीं। मैं अभी भी async विधियों पर अनुबंध से बचें। और मैं अब भी उम्मीद कर रहा हूं कि एमएस इसे ठीक करेगा। :) –

+0

तब से स्थिति बदल गई है। नीचे मेरा जवाब देखें। –

2

इस टाइप लेकिन "पोस्ट" हिट करने के लिए ... :)

इस समय इस बात के लिए विशेष समर्थन नहीं है भूल गया। ,

public static Task<int> Do() 
{ 
    Contract.Ensures(Contract.Result<Task<int>>() != null); 
    Contract.Ensures(Contract.Result<Task<int>>().Result > 0); 

    return Task.Factory.StartNew(() => { Thread.Sleep(3000); return 2; }); 
} 

public static void Main(string[] args) 
{ 
    var x = Do(); 
    Console.WriteLine("processing"); 
    Console.WriteLine(x.Result); 
} 

हालांकि: - सबसे अच्छा आप कर सकते हैं कुछ इस तरह है (यह संभव है rewriter async CTP के तहत अलग ढंग से काम करेंगे, मैं इसे अभी तक प्रयास नहीं किया है async कीवर्ड का उपयोग नहीं है, लेकिन एक ही विचार) इसका मतलब यह है कि 'async' विधि वास्तव में कार्य समाप्त होने तक वापस नहीं आती है, इसलिए "प्रोसेसिंग" मुद्रित नहीं किया जाएगा जब तक कि 3 सेकंड बीत चुके न हों। यह उन तरीकों के साथ समस्या के समान है जो IEnumerable s — पर लौटने के लिए अनुबंध को IEnumerable में सभी आइटमों को गिनने के लिए है, यह सुनिश्चित करने के लिए कि स्थिति वास्तव में सभी वस्तुओं का उपयोग नहीं करेगी।

आप अपने अनुबंध मोड को Preconditions पर बदलकर इस पर काम कर सकते हैं, लेकिन इसका मतलब है कि पोस्ट-कंडीशन की वास्तव में जांच नहीं की जाएगी।

स्थैतिक चेकर भी लैम्ब्डा के साथ Result को कनेक्ट नहीं कर सकता है, इसलिए आपको "अनुमोदित सुनिश्चित किया गया" संदेश प्राप्त होगा। (सामान्य रूप से स्थैतिक चेकर किसी भी तरह lambdas/प्रतिनिधियों के बारे में चीजें साबित नहीं करता है।)

मुझे लगता है कि कार्य/प्रतीक्षा के लिए उचित समर्थन प्राप्त करना है, कोड अनुबंध टीम को केवल पूर्व शर्त जांच जोड़ने के लिए विशेष मामले कार्य करना होगा Result फ़ील्ड की पहुंच पर।

+0

जानकारी के लिए धन्यवाद - मैंने आलसी लोड किए गए संग्रहों के बारे में भी सोचा नहीं था: -/ –

+0

हाँ, आप एक स्विच (स्किप क्वालिफायर) चालू कर सकते हैं जो उनके साथ समस्याएं होने से बचने के लिए 'Contract.ForAll' अनुबंधों को अनदेखा कर देगा। कार्य (अभी तक) के लिए ऐसा कोई स्विच नहीं है। – porges

0

इस पुराने धागा करने के लिए नए उत्तर पोस्ट के रूप में यह टास्क लौटने async तरीकों पर CodeContract और Async के बारे में सवाल करने के लिए पहले जवाब के रूप में गूगल द्वारा दिया जाता है

curently अनुबंध सही ढंग से काम कर रहे हैं, और उन्हें बचने के लिए कोई जरूरत नहीं है । async विधि के लिए

Standart अनुबंध:

[ContractClass(typeof(ContractClassForIFoo))] 
public interface IFoo 
{ 
    Task<object> MethodAsync(); 
} 


[ContractClassFor(typeof(IFoo))] 
internal abstract class ContractClassForIFoo : IFoo 
{ 
    #region Implementation of IFoo 

    public Task<object> MethodAsync() 
    { 
     Contract.Ensures(Contract.Result<Task<object>>() != null); 
     Contract.Ensures(Contract.Result<Task<object>>().Status != TaskStatus.Created); 
     Contract.Ensures(Contract.Result<object>() != null); 
     throw new NotImplementedException(); 
    } 

    #endregion 
} 

public class Foo : IFoo 
{ 
    public async Task<object> MethodAsync() 
    { 
     var result = await Task.FromResult(new object()); 
     return result; 
    } 
} 

आपको लगता है कि अनुबंध मैं सहमत हूँ यह कम से कम भ्रामक लग रहा है सही नहीं लगती है, लेकिन यह काम करता है तो। और ऐसा लगता है कि अनुबंध पुनरावर्तक कार्य समय से पहले मूल्यांकन का मूल्यांकन नहीं करता है।

जैसे स्टीफन ने कुछ संदेह उठाए, मेरे मामले में कुछ और परीक्षण और अनुबंध किए गए, उनकी बात सही ढंग से हुई।

कोड के परीक्षण के लिए इस्तेमाल किया:

public static class ContractsAbbreviators 
{ 
    [ContractAbbreviator] 
    public static void EnsureTaskIsStarted() 
    { 
     Contract.Ensures(Contract.Result<Task>() != null); 
     Contract.Ensures(Contract.Result<Task>().Status != TaskStatus.Created); 
    } 

} 

[ContractClass(typeof(ContractClassForIFoo))] 
public interface IFoo 
{ 
    Task<int> MethodAsync(int val); 
} 

[ContractClassFor(typeof(IFoo))] 
internal abstract class ContractClassForIFoo : IFoo 
{ 
    public Task<int> MethodAsync(int val) 
    { 
     Contract.Requires(val >= 0); 
     ContractsAbbreviators.EnsureTaskIsStarted(); 
     Contract.Ensures(Contract.Result<int>() == val); 
     Contract.Ensures(Contract.Result<int>() >= 5); 
     Contract.Ensures(Contract.Result<int>() < 10); 
     throw new NotImplementedException(); 
    } 
} 

public class FooContractFailTask : IFoo 
{ 
    public Task<int> MethodAsync(int val) 
    { 
     return new Task<int>(() => val); 
     // esnure raises exception // Contract.Ensures(Contract.Result<Task>().Status != TaskStatus.Created); 
    } 
} 

public class FooContractFailTaskResult : IFoo 
{ 
    public async Task<int> MethodAsync(int val) 
    { 
     await Task.Delay(val).ConfigureAwait(false); 
     return val + 1; 
     // esnure raises exception // Contract.Ensures(Contract.Result<int>() == val); 
    } 
} 

public class Foo : IFoo 
{ 
    public async Task<int> MethodAsync(int val) 
    { 
     const int maxDeapth = 9; 

     await Task.Delay(val).ConfigureAwait(false); 

     if (val < maxDeapth) 
     { 
      await MethodAsync(val + 1).ConfigureAwait(false); 
     } 

     return val; 
    } 
} 
+0

लेकिन आप अनुबंधों को व्यक्त नहीं कर सकते हैं जैसे "पूर्णांक सीमा [5, 10) में होगा, और मेरा मानना ​​है कि कार्यान्वयन निकाय में व्यक्त पूर्व शर्त भी उम्मीद के अनुसार काम नहीं करती है। –

+0

यह मेरे लिए काम नहीं करता है। अगर मेरे पास 'कार्य ' वापस लौटने वाली एसिंक विधि है और मैं 'अनुबंध' पूछता हूं (अनुबंध। परिणाम ()! = शून्य) शुरुआत में, यह 'BadImageFormatException' का कारण बनता है। – piedar

संबंधित मुद्दे