Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy doesn't preserve contstructor. #1071

Closed
jamesmontemagno opened this issue Apr 7, 2020 · 2 comments
Closed

Lazy doesn't preserve contstructor. #1071

jamesmontemagno opened this issue Apr 7, 2020 · 2 comments

Comments

@jamesmontemagno
Copy link
Member

jamesmontemagno commented Apr 7, 2020

On Xamarin.iOS we found this when we turn on the linker with the following code that the constructor will get linked out and will crash the app:

The lazily-initialized type does not have a public, parameterless constructor.

public static partial class TextToSpeech
    {
        static readonly Lazy<AVSpeechSynthesizer> speechSynthesizer = new Lazy<AVSpeechSynthesizer>();
 internal static async Task PlatformSpeakAsync(string text, SpeechOptions options, CancellationToken cancelToken = default)
        {
            using (var speechUtterance = GetSpeechUtterance(text, options))
            {
                await SpeakUtterance(speechUtterance, cancelToken);
            }
        }

        static AVSpeechUtterance GetSpeechUtterance(string text, SpeechOptions options)
        {
            var speechUtterance = new AVSpeechUtterance(text);

            if (options != null)
            {
                // null voice if fine - it is the default
                speechUtterance.Voice =
                    AVSpeechSynthesisVoice.FromLanguage(options.Locale?.Language) ??
                    AVSpeechSynthesisVoice.FromLanguage(AVSpeechSynthesisVoice.CurrentLanguageCode);

                // the platform has a range of 0.5 - 2.0
                // anything lower than 0.5 is set to 0.5
                if (options.Pitch.HasValue)
                    speechUtterance.PitchMultiplier = options.Pitch.Value;

                if (options.Volume.HasValue)
                    speechUtterance.Volume = options.Volume.Value;
            }

            return speechUtterance;
        }

        internal static async Task SpeakUtterance(AVSpeechUtterance speechUtterance, CancellationToken cancelToken)
        {
            var tcsUtterance = new TaskCompletionSource<bool>();
            try
            {
                speechSynthesizer.Value.DidFinishSpeechUtterance += OnFinishedSpeechUtterance;
                speechSynthesizer.Value.SpeakUtterance(speechUtterance);
                using (cancelToken.Register(TryCancel))
                {
                    await tcsUtterance.Task;
                }
            }
            finally
            {
                speechSynthesizer.Value.DidFinishSpeechUtterance -= OnFinishedSpeechUtterance;
            }

            void TryCancel()
            {
                speechSynthesizer.Value?.StopSpeaking(AVSpeechBoundary.Word);
                tcsUtterance?.TrySetResult(true);
            }

            void OnFinishedSpeechUtterance(object sender, AVSpeechSynthesizerUteranceEventArgs args)
            {
                if (speechUtterance == args.Utterance)
                    tcsUtterance?.TrySetResult(true);
            }
        }
}

From: xamarin/Essentials#1207

@marek-safar
Copy link
Contributor

This will be addressed by #988 for .NET5

/cc @vitek-karas

@marek-safar
Copy link
Contributor

Closing as all the linker infrastructure for this landed in .NET 5.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants