سؤال

أنا أستخدم مكتبة PCLStorage في مشروعي حتى أتمكن من الوصول إلى نظام الملفات من مكتبة PCL الخاصة بي.أحاول قراءة الملف على النحو التالي:

static async Task<T> LoadAsync<T> (string fileName) where T : class
    {
        var rootFolder = FileSystem.Current.LocalStorage; // debugger stops here
        var m5cacheFolder = await rootFolder.GetFolderAsync (CacheFolderName); // but instead of going to this line, jumps to end of this method
        var userInfoFile = await m5cacheFolder.GetFileAsync (fileName);
        var userInfoFileContent = await userInfoFile.ReadAllTextAsync ();
        var stringReader = new StringReader (userInfoFileContent);
        var serializer = new XmlSerializer (typeof(T));
        return (T)serializer.Deserialize (stringReader);
    }

نظرًا لأن PCLStorage غير متزامن وأريد استخدامه في رمز متزامن فأنا أسميه على النحو التالي:

var task = LoadAsync<User> (UserInfoFileName);
user = task.Result;

المشكلة هي أن التطبيق بأكمله يتجمد عندما أحاول تنفيذ هذا الرمز.كما هو موضح في التعليقات أعلاه، لم يتم تنفيذ التعليمات البرمجية في أسلوب LoadAsync.أنا أستخدم الإصدار الأحدث Xamarin 3.تمت الإشارة إلى مكتبة PCL الخاصة بي في مشروع Xamarin iOS.يحتوي كلا المشروعين على إشارات إلى PCLStorage من خلال الكتلة.

ومن ناحية أخرى يتم تنفيذ التعليمات البرمجية التالية بشكل صحيح:

static async void PersistAsync (object obj, string fileName)
    {
        var rootFolder = FileSystem.Current.LocalStorage;
        var m5cacheFolder = await rootFolder.CreateFolderAsync (CacheFolderName, CreationCollisionOption.OpenIfExists);
        var userInfoFile = await m5cacheFolder.CreateFileAsync (fileName, CreationCollisionOption.ReplaceExisting);
        var serializer = new XmlSerializer (obj.GetType ());
        var stringWriter = new StringWriter ();
        serializer.Serialize (stringWriter, obj);
        await userInfoFile.WriteAllTextAsync (stringWriter.ToString ());
    }
هل كانت مفيدة؟

المحلول

هذه دائمًا وصفة محتملة لكارثة:

var task = LoadAsync<User>(UserInfoFileName);
user = task.Result;

إذا حدث هذا في سلسلة رسائل واجهة المستخدم، فأنت تقوم بشكل أساسي بحظر سلسلة رسائل واجهة المستخدم حتى تكتمل المهمة - ولكن المهمة ستحتاج إلى تنفيذ استمراراتها على سلسلة رسائل واجهة المستخدم أيضًا.لقد وصلت إلى طريق مسدود.

في الأساس، يجب أن تحاول تنظيم تطبيقك ليشمل عدم التزامن بشكل أكبر.أنت استطاع يستخدم Task.ConfigureAwait() لجدولة الاستمرارات في LoadAsync للتنفيذ على سلاسل رسائل تجمع الخيوط بدلاً من ذلك، لكنك ستظل تحظر واجهة المستخدم حتى تكتمل، وهو ما يتعارض مع روح عدم التزامن.

يعتبر عدم التزامن منتشرًا إلى حد ما - إذا حاولت القيام به فقط واحد جزء من تطبيقك غير متزامن، فستجد صعوبة في ذلك.يجب أن تكون غير متزامن طوال الطريق، على الأقل فيما يتعلق بعمليات واجهة المستخدم.

(إذا قمت بحظر انتظار المهمة التي تم إرجاعها بواسطة PersistAsync سيكون لديك مشكلة مماثلة، بالمناسبة.)

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top