From be59ee945a5ead6fe5d8d7cbeaad058e8180bf7f Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Mon, 27 Apr 2020 22:22:32 +0900
Subject: [PATCH 1/4] Add taiko hit explosion skinning support

---
 .../Skinning/TestSceneHitExplosion.cs         | 79 +++++++++++++++++++
 .../Skinning/LegacyHitExplosion.cs            | 29 +++++++
 .../Skinning/TaikoLegacySkinTransformer.cs    | 27 +++++++
 .../TaikoSkinComponents.cs                    |  5 +-
 .../UI/DefaultHitExplosion.cs                 | 54 +++++++++++++
 osu.Game.Rulesets.Taiko/UI/HitExplosion.cs    | 50 ++++++------
 osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs  |  7 +-
 7 files changed, 221 insertions(+), 30 deletions(-)
 create mode 100644 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs
 create mode 100644 osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs
 create mode 100644 osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs

diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs
new file mode 100644
index 0000000000..ca0c60b67a
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs
@@ -0,0 +1,79 @@
+// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Beatmaps;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Rulesets.Taiko.Objects.Drawables;
+using osu.Game.Rulesets.Taiko.Skinning;
+using osu.Game.Rulesets.Taiko.UI;
+
+namespace osu.Game.Rulesets.Taiko.Tests.Skinning
+{
+    [TestFixture]
+    public class TestSceneHitExplosion : TaikoSkinnableTestScene
+    {
+        public override IReadOnlyList<Type> RequiredTypes => base.RequiredTypes.Concat(new[]
+        {
+            typeof(HitExplosion),
+            typeof(LegacyHitExplosion),
+            typeof(DefaultHitExplosion),
+        }).ToList();
+
+        [BackgroundDependencyLoader]
+        private void load()
+        {
+            AddStep("Great", () => SetContents(() => getContentFor(HitResult.Great)));
+            AddStep("Good", () => SetContents(() => getContentFor(HitResult.Good)));
+            AddStep("Miss", () => SetContents(() => getContentFor(HitResult.Miss)));
+        }
+
+        private Drawable getContentFor(HitResult type)
+        {
+            DrawableTaikoHitObject hit;
+
+            return new Container
+            {
+                RelativeSizeAxes = Axes.Both,
+                Children = new Drawable[]
+                {
+                    hit = createHit(type),
+                    new HitExplosion(hit)
+                    {
+                        Anchor = Anchor.Centre,
+                        Origin = Anchor.Centre,
+                    }
+                }
+            };
+        }
+
+        private DrawableTaikoHitObject createHit(HitResult type) => new TestDrawableHit(new Hit { StartTime = Time.Current }, type);
+
+        private class TestDrawableHit : DrawableTaikoHitObject
+        {
+            private readonly HitResult type;
+
+            public TestDrawableHit(Hit hit, HitResult type)
+                : base(hit)
+            {
+                this.type = type;
+            }
+
+            [BackgroundDependencyLoader]
+            private void load()
+            {
+                Result.Type = type;
+            }
+
+            public override bool OnPressed(TaikoAction action) => false;
+        }
+    }
+}
diff --git a/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs
new file mode 100644
index 0000000000..d29b574866
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Skinning/LegacyHitExplosion.cs
@@ -0,0 +1,29 @@
+// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+
+namespace osu.Game.Rulesets.Taiko.Skinning
+{
+    public class LegacyHitExplosion : CompositeDrawable
+    {
+        public LegacyHitExplosion(Drawable sprite)
+        {
+            InternalChild = sprite;
+
+            Anchor = Anchor.Centre;
+            Origin = Anchor.Centre;
+
+            AutoSizeAxes = Axes.Both;
+        }
+
+        protected override void LoadComplete()
+        {
+            base.LoadComplete();
+
+            this.FadeIn(120);
+            this.ScaleTo(0.6f).Then().ScaleTo(1, 240, Easing.OutElastic);
+        }
+    }
+}
diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
index 447d6ae455..bea1c6bdcf 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
@@ -81,11 +81,38 @@ namespace osu.Game.Rulesets.Taiko.Skinning
                         return new LegacyBarLine();
 
                     return null;
+
+                case TaikoSkinComponents.TaikoExplosionGood:
+                case TaikoSkinComponents.TaikoExplosionGreat:
+                case TaikoSkinComponents.TaikoExplosionMiss:
+
+                    var sprite = this.GetAnimation(getHitname(taikoComponent.Component), true, false);
+                    if (sprite != null)
+                        return new LegacyHitExplosion(sprite);
+
+                    return null;
             }
 
             return source.GetDrawableComponent(component);
         }
 
+        private string getHitname(TaikoSkinComponents component)
+        {
+            switch (component)
+            {
+                case TaikoSkinComponents.TaikoExplosionMiss:
+                    return "taiko-hit0";
+
+                case TaikoSkinComponents.TaikoExplosionGood:
+                    return "taiko-hit100";
+
+                case TaikoSkinComponents.TaikoExplosionGreat:
+                    return "taiko-hit300";
+            }
+
+            return string.Empty;
+        }
+
         public Texture GetTexture(string componentName) => source.GetTexture(componentName);
 
         public SampleChannel GetSample(ISampleInfo sampleInfo) => source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
diff --git a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs
index a90ce608b2..fd091f97d0 100644
--- a/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs
+++ b/osu.Game.Rulesets.Taiko/TaikoSkinComponents.cs
@@ -14,6 +14,9 @@ namespace osu.Game.Rulesets.Taiko
         HitTarget,
         PlayfieldBackgroundLeft,
         PlayfieldBackgroundRight,
-        BarLine
+        BarLine,
+        TaikoExplosionMiss,
+        TaikoExplosionGood,
+        TaikoExplosionGreat,
     }
 }
diff --git a/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs
new file mode 100644
index 0000000000..aa444d0494
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/UI/DefaultHitExplosion.cs
@@ -0,0 +1,54 @@
+// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.Taiko.Objects;
+using osuTK.Graphics;
+
+namespace osu.Game.Rulesets.Taiko.UI
+{
+    internal class DefaultHitExplosion : CircularContainer
+    {
+        [Resolved]
+        private DrawableHitObject judgedObject { get; set; }
+
+        [BackgroundDependencyLoader]
+        private void load(OsuColour colours)
+        {
+            RelativeSizeAxes = Axes.Both;
+
+            BorderColour = Color4.White;
+            BorderThickness = 1;
+
+            Alpha = 0.15f;
+            Masking = true;
+
+            if (judgedObject.Result.Type == HitResult.Miss)
+                return;
+
+            bool isRim = (judgedObject.HitObject as Hit)?.Type == HitType.Rim;
+
+            InternalChildren = new[]
+            {
+                new Box
+                {
+                    RelativeSizeAxes = Axes.Both,
+                    Colour = isRim ? colours.BlueDarker : colours.PinkDarker,
+                }
+            };
+        }
+
+        protected override void LoadComplete()
+        {
+            base.LoadComplete();
+
+            this.ScaleTo(3f, 1000, Easing.OutQuint);
+        }
+    }
+}
diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
index fbaae7e322..9bef93d834 100644
--- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
+++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
@@ -1,15 +1,15 @@
 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
 // See the LICENCE file in the repository root for full licence text.
 
+using System;
 using osuTK;
-using osuTK.Graphics;
 using osu.Framework.Allocation;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics;
 using osu.Game.Rulesets.Objects.Drawables;
+using osu.Game.Rulesets.Scoring;
 using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Skinning;
 
 namespace osu.Game.Rulesets.Taiko.UI
 {
@@ -20,15 +20,12 @@ namespace osu.Game.Rulesets.Taiko.UI
     {
         public override bool RemoveWhenNotAlive => true;
 
+        [Cached(typeof(DrawableHitObject))]
         public readonly DrawableHitObject JudgedObject;
-        private readonly HitType type;
 
-        private readonly Box innerFill;
-
-        public HitExplosion(DrawableHitObject judgedObject, HitType type)
+        public HitExplosion(DrawableHitObject judgedObject)
         {
             JudgedObject = judgedObject;
-            this.type = type;
 
             Anchor = Anchor.Centre;
             Origin = Anchor.Centre;
@@ -37,35 +34,36 @@ namespace osu.Game.Rulesets.Taiko.UI
             Size = new Vector2(TaikoHitObject.DEFAULT_SIZE);
 
             RelativePositionAxes = Axes.Both;
-
-            BorderColour = Color4.White;
-            BorderThickness = 1;
-
-            Alpha = 0.15f;
-            Masking = true;
-
-            Children = new[]
-            {
-                innerFill = new Box
-                {
-                    RelativeSizeAxes = Axes.Both,
-                }
-            };
         }
 
         [BackgroundDependencyLoader]
-        private void load(OsuColour colours)
+        private void load()
         {
-            innerFill.Colour = type == HitType.Rim ? colours.BlueDarker : colours.PinkDarker;
+            Child = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(JudgedObject.Result?.Type ?? HitResult.Great)), _ => new DefaultHitExplosion());
+        }
+
+        private TaikoSkinComponents getComponentName(HitResult resultType)
+        {
+            switch (resultType)
+            {
+                case HitResult.Miss:
+                    return TaikoSkinComponents.TaikoExplosionMiss;
+
+                case HitResult.Good:
+                    return TaikoSkinComponents.TaikoExplosionGood;
+
+                case HitResult.Great:
+                    return TaikoSkinComponents.TaikoExplosionGreat;
+            }
+
+            throw new ArgumentException("Invalid result type", nameof(resultType));
         }
 
         protected override void LoadComplete()
         {
             base.LoadComplete();
 
-            this.ScaleTo(3f, 1000, Easing.OutQuint);
             this.FadeOut(500);
-
             Expire(true);
         }
 
diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
index 4bc6cb8e4b..6a78c0a1fb 100644
--- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
+++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs
@@ -185,7 +185,6 @@ namespace osu.Game.Rulesets.Taiko.UI
                     var drawableTick = (DrawableDrumRollTick)judgedObject;
 
                     addDrumRollHit(drawableTick);
-                    addExplosion(drawableTick, drawableTick.JudgementType);
                     break;
 
                 default:
@@ -200,7 +199,9 @@ namespace osu.Game.Rulesets.Taiko.UI
                     if (!result.IsHit)
                         break;
 
-                    addExplosion(judgedObject, (judgedObject.HitObject as Hit)?.Type ?? HitType.Centre);
+                    var type = (judgedObject.HitObject as Hit)?.Type ?? HitType.Centre;
+
+                    addExplosion(judgedObject, type);
                     break;
             }
         }
@@ -210,7 +211,7 @@ namespace osu.Game.Rulesets.Taiko.UI
 
         private void addExplosion(DrawableHitObject drawableObject, HitType type)
         {
-            hitExplosionContainer.Add(new HitExplosion(drawableObject, type));
+            hitExplosionContainer.Add(new HitExplosion(drawableObject));
             if (drawableObject.HitObject.Kiai)
                 kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type));
         }

From df55439f8b15d167491fba706987278f50bd4ac0 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Mon, 27 Apr 2020 23:24:12 +0900
Subject: [PATCH 2/4] Remove undetected usings

---
 osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs
index ca0c60b67a..3a9779c93b 100644
--- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs
@@ -8,8 +8,6 @@ using NUnit.Framework;
 using osu.Framework.Allocation;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Game.Beatmaps;
-using osu.Game.Beatmaps.ControlPoints;
 using osu.Game.Rulesets.Scoring;
 using osu.Game.Rulesets.Taiko.Objects;
 using osu.Game.Rulesets.Taiko.Objects.Drawables;

From f387fe310f04cf87f182961e6209477bb6a9394a Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Tue, 28 Apr 2020 11:07:31 +0900
Subject: [PATCH 3/4] Fix regressing hits test

---
 .../DrawableTestHit.cs                        | 29 +++++++++++++++++++
 .../Skinning/TestSceneHitExplosion.cs         | 21 +-------------
 .../TestSceneHits.cs                          | 12 +++-----
 3 files changed, 34 insertions(+), 28 deletions(-)
 create mode 100644 osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs

diff --git a/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs
new file mode 100644
index 0000000000..1db07b3244
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/DrawableTestHit.cs
@@ -0,0 +1,29 @@
+// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Rulesets.Taiko.Objects.Drawables;
+
+namespace osu.Game.Rulesets.Taiko.Tests
+{
+    internal class DrawableTestHit : DrawableTaikoHitObject
+    {
+        private readonly HitResult type;
+
+        public DrawableTestHit(Hit hit, HitResult type = HitResult.Great)
+            : base(hit)
+        {
+            this.type = type;
+        }
+
+        [BackgroundDependencyLoader]
+        private void load()
+        {
+            Result.Type = type;
+        }
+
+        public override bool OnPressed(TaikoAction action) => false;
+    }
+}
diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs
index 3a9779c93b..791c438c94 100644
--- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneHitExplosion.cs
@@ -53,25 +53,6 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
             };
         }
 
-        private DrawableTaikoHitObject createHit(HitResult type) => new TestDrawableHit(new Hit { StartTime = Time.Current }, type);
-
-        private class TestDrawableHit : DrawableTaikoHitObject
-        {
-            private readonly HitResult type;
-
-            public TestDrawableHit(Hit hit, HitResult type)
-                : base(hit)
-            {
-                this.type = type;
-            }
-
-            [BackgroundDependencyLoader]
-            private void load()
-            {
-                Result.Type = type;
-            }
-
-            public override bool OnPressed(TaikoAction action) => false;
-        }
+        private DrawableTaikoHitObject createHit(HitResult type) => new DrawableTestHit(new Hit { StartTime = Time.Current }, type);
     }
 }
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs
index 23adb79083..44452d70c1 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneHits.cs
@@ -149,6 +149,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
 
             var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
 
+            Add(h);
+
             ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult });
         }
 
@@ -164,6 +166,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
 
             var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Good ? -0.1f : -0.05f, hitResult == HitResult.Good ? 0.1f : 0.05f) };
 
+            Add(h);
+
             ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult });
             ((TaikoPlayfield)drawableRuleset.Playfield).OnNewResult(new TestStrongNestedHit(h), new JudgementResult(new HitObject(), new TaikoStrongJudgement()) { Type = HitResult.Great });
         }
@@ -249,13 +253,5 @@ namespace osu.Game.Rulesets.Taiko.Tests
 
             public override bool OnPressed(TaikoAction action) => false;
         }
-
-        private class DrawableTestHit : DrawableHitObject<TaikoHitObject>
-        {
-            public DrawableTestHit(TaikoHitObject hitObject)
-                : base(hitObject)
-            {
-            }
-        }
     }
 }

From 84641765c5858976fc2fa43606e77f60d4f7e7f1 Mon Sep 17 00:00:00 2001
From: Dean Herbert <pe@ppy.sh>
Date: Tue, 28 Apr 2020 11:08:19 +0900
Subject: [PATCH 4/4] Adjust exceptions and fix capitalisation

---
 .../Skinning/TaikoLegacySkinTransformer.cs                 | 7 ++++---
 osu.Game.Rulesets.Taiko/UI/HitExplosion.cs                 | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
index bea1c6bdcf..f0df612e18 100644
--- a/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
+++ b/osu.Game.Rulesets.Taiko/Skinning/TaikoLegacySkinTransformer.cs
@@ -1,6 +1,7 @@
 // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
 // See the LICENCE file in the repository root for full licence text.
 
+using System;
 using System.Collections.Generic;
 using osu.Framework.Audio.Sample;
 using osu.Framework.Bindables;
@@ -86,7 +87,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning
                 case TaikoSkinComponents.TaikoExplosionGreat:
                 case TaikoSkinComponents.TaikoExplosionMiss:
 
-                    var sprite = this.GetAnimation(getHitname(taikoComponent.Component), true, false);
+                    var sprite = this.GetAnimation(getHitName(taikoComponent.Component), true, false);
                     if (sprite != null)
                         return new LegacyHitExplosion(sprite);
 
@@ -96,7 +97,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning
             return source.GetDrawableComponent(component);
         }
 
-        private string getHitname(TaikoSkinComponents component)
+        private string getHitName(TaikoSkinComponents component)
         {
             switch (component)
             {
@@ -110,7 +111,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning
                     return "taiko-hit300";
             }
 
-            return string.Empty;
+            throw new ArgumentOutOfRangeException(nameof(component), "Invalid result type");
         }
 
         public Texture GetTexture(string componentName) => source.GetTexture(componentName);
diff --git a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
index 9bef93d834..35a54d6ea7 100644
--- a/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
+++ b/osu.Game.Rulesets.Taiko/UI/HitExplosion.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Taiko.UI
                     return TaikoSkinComponents.TaikoExplosionGreat;
             }
 
-            throw new ArgumentException("Invalid result type", nameof(resultType));
+            throw new ArgumentOutOfRangeException(nameof(resultType), "Invalid result type");
         }
 
         protected override void LoadComplete()