Другими словами, правильный метод расширения вызывается, когда в первую очередь используется var . Затем код не удается при вызове метода, потому что мы переходим от «неявного» к «абстрактному», потому что аргумент метода не может быть var type.
Я думаю, что это есть чем заняться со статическим анализом, поскольку изменение var на foo.fooclass или foo.fooa приводит к двум различным результатам (успех или исключение).
the Базовый тип var не изменяется.
using System;
namespace Foo
{
public abstract class FooClass {}
public class FooA:FooClass {}
public class FooB:FooClass {}
}
namespace Bar
{
public abstract class BarClass {}
public class BarA:BarClass {}
public class BarB:BarClass {}
}
namespace AppLogic
{
public static class App
{
public static void Main()
{
var f = new Foo.FooA();
Bar.BarClass b = f.Parse();
Bar.BarClass b2 = GetBar(f);
}
static Bar.BarClass GetBar(Foo.FooClass f)
{
return f.Parse();
}
}
public static class Extensions
{
public static Bar.BarA Parse(this Foo.FooA foo)
{
Console.WriteLine("Got a BarA");
return new Bar.BarA();
}
public static Bar.BarClass Parse(this Foo.FooClass foo)
{
Console.WriteLine("Got a BarClass");
throw new InvalidOperationException();
}
public static Bar.BarB Parse(this Foo.FooB foo)
{
Console.WriteLine("Got a BarB");
return new Bar.BarB();
}
}
}
< /code>
Редактировать: < /p>
Этот вопрос был закрыт, и следующая ссылка была предоставлена для справки: < /p>
расширение Метод переоценка < /p>
В связанном вопросе и ответах не было дано практического варианта для имитации «виртуальная диспетчерская», которая является предметом этого поста и прецедента. < /P>
Классы Foo/Bar были слегка отрегулированы для ясности. Последствия для производительности находятся в центре внимания ниже. Эта реализация ограничена закрытым набором типов, которые вы управляете. < /P>
// Example
Foo f = new Foo1();
Bar b = f.ParseDict();
Foo f2 = new Foo1();
Bar b = f.ParseSwitch();
// Minimal implementation
static class Extensions
{
static Dictionary VTable = new Dictionary
{
{typeof(Foo1), ()=> new Bar1() },
{typeof(Foo2), ()=> new Bar2() },
{typeof(Foo3), ()=> new Bar3() },
{typeof(Foo4), ()=> new Bar4() },
{typeof(Foo5), ()=> new Bar5() },
{typeof(Foo6), ()=> new Bar6() },
{typeof(Foo7), ()=> new Bar7() },
{typeof(Foo8), ()=> new Bar8() },
{typeof(Foo9), ()=> new Bar9() },
{typeof(Foo10), ()=> new Bar10() },
};
public static Bar ParseDict(this Foo foo) => VTable[foo.GetType()]();
public static Bar ParseSwitch(this Foo foo) => foo switch
{
Foo1 => new Bar1(),
Foo2 => new Bar2(),
Foo3 => new Bar3(),
Foo4 => new Bar4(),
Foo5 => new Bar5(),
Foo6 => new Bar6(),
Foo7 => new Bar7(),
Foo8 => new Bar8(),
Foo9 => new Bar9(),
Foo10 => new Bar10(),
_=> throw new ArgumentOutOfRangeException()
};
}
abstract class Foo { }
class Foo1:Foo{ }
class Foo2 : Foo { }
class Foo3 : Foo { }
class Foo4 : Foo { }
class Foo5 : Foo { }
class Foo6 : Foo { }
class Foo7 : Foo { }
class Foo8 : Foo { }
class Foo9 : Foo { }
class Foo10 : Foo { }
abstract class Bar { }
class Bar1 : Bar { }
class Bar2 : Bar { }
class Bar3 : Bar { }
class Bar4 : Bar { }
class Bar5 : Bar { }
class Bar6 : Bar { }
class Bar7 : Bar { }
class Bar8 : Bar { }
class Bar9 : Bar { }
class Bar10 : Bar { }
< /code>
Ниже эталонный эталон вызывает метод расширения 100 000 раз. Различные классы Foo (то есть FOO1-FOO9) использовались, чтобы продемонстрировать, что блок Switch
выполняет поиск O (n), тогда как словарь-это (1) поиск.
Реализация словаря демонстрирует постоянное время O (1) производительность. < /P>
bend_dict_foo1 < /td>
806.9 Us < /td>
9,93 США < /td>
9.29 Us < /td>
183.5938 < /td>
2,29 мб < /td>
< /tr>
bend_dict_foo5 < /td>
806.8 Us < /td>
4.72 US < /td>
4.42 Us < /td>
183.5938 < /td>
2,29 мб < /td>
< /tr>
bend_dict_foo9 < /td>
793.4 Us < /td>
5.30 Us < /td> 4.70 us < /td>
183.5938 < /td>
2,29 мб
< P> Реализация Switch демонстрирует линейную производительность O (n). Как видите, корпус переключения быстрее, если количество типов составляет около 5 или менее. >
В приведенном ниже коде можно ли переписать метод getbar () , чтобы не бросить исключение? />[code]Got a BarA Got a BarClass [/code] Другими словами, правильный метод расширения вызывается, когда в первую очередь используется var . Затем код не удается при вызове метода, потому что мы переходим от «неявного» к «абстрактному», потому что аргумент метода не может быть var type. Я думаю, что это есть чем заняться со статическим анализом, поскольку изменение var на foo.fooclass или foo.fooa приводит к двум различным результатам (успех или исключение). the Базовый тип var не изменяется. [code]using System;
namespace Foo { public abstract class FooClass {}
public class FooA:FooClass {}
public class FooB:FooClass {}
}
namespace Bar { public abstract class BarClass {}
public class BarA:BarClass {}
public class BarB:BarClass {}
}
namespace AppLogic { public static class App { public static void Main() { var f = new Foo.FooA(); Bar.BarClass b = f.Parse(); Bar.BarClass b2 = GetBar(f);
public static class Extensions { public static Bar.BarA Parse(this Foo.FooA foo) { Console.WriteLine("Got a BarA"); return new Bar.BarA(); }
public static Bar.BarClass Parse(this Foo.FooClass foo) { Console.WriteLine("Got a BarClass"); throw new InvalidOperationException(); }
public static Bar.BarB Parse(this Foo.FooB foo) { Console.WriteLine("Got a BarB"); return new Bar.BarB(); } } } < /code> Редактировать: < /p> Этот вопрос был закрыт, и следующая ссылка была предоставлена для справки: < /p> расширение Метод переоценка < /p> В связанном вопросе и ответах не было дано практического варианта для имитации «виртуальная диспетчерская», которая является предметом этого поста и прецедента. < /P> Классы Foo/Bar были слегка отрегулированы для ясности. Последствия для производительности находятся в центре внимания ниже. Эта реализация ограничена закрытым набором типов, которые вы управляете. < /P> // Example
Foo f = new Foo1(); Bar b = f.ParseDict();
Foo f2 = new Foo1(); Bar b = f.ParseSwitch();
// Minimal implementation
static class Extensions { static Dictionary VTable = new Dictionary { {typeof(Foo1), ()=> new Bar1() }, {typeof(Foo2), ()=> new Bar2() }, {typeof(Foo3), ()=> new Bar3() }, {typeof(Foo4), ()=> new Bar4() }, {typeof(Foo5), ()=> new Bar5() }, {typeof(Foo6), ()=> new Bar6() }, {typeof(Foo7), ()=> new Bar7() }, {typeof(Foo8), ()=> new Bar8() }, {typeof(Foo9), ()=> new Bar9() }, {typeof(Foo10), ()=> new Bar10() }, };
public static Bar ParseDict(this Foo foo) => VTable[foo.GetType()]();
public static Bar ParseSwitch(this Foo foo) => foo switch { Foo1 => new Bar1(), Foo2 => new Bar2(), Foo3 => new Bar3(), Foo4 => new Bar4(), Foo5 => new Bar5(), Foo6 => new Bar6(), Foo7 => new Bar7(), Foo8 => new Bar8(), Foo9 => new Bar9(), Foo10 => new Bar10(), _=> throw new ArgumentOutOfRangeException() };
}
abstract class Foo { } class Foo1:Foo{ } class Foo2 : Foo { } class Foo3 : Foo { }
class Foo4 : Foo { } class Foo5 : Foo { } class Foo6 : Foo { } class Foo7 : Foo { } class Foo8 : Foo { } class Foo9 : Foo { } class Foo10 : Foo { }
abstract class Bar { } class Bar1 : Bar { } class Bar2 : Bar { }
class Bar3 : Bar { } class Bar4 : Bar { } class Bar5 : Bar { } class Bar6 : Bar { } class Bar7 : Bar { } class Bar8 : Bar { } class Bar9 : Bar { } class Bar10 : Bar { } < /code> Ниже эталонный эталон вызывает метод расширения 100 000 раз. Различные классы Foo (то есть FOO1-FOO9) использовались, чтобы продемонстрировать, что блок Switch [/code] выполняет поиск O (n), тогда как словарь-это (1) поиск. Реализация словаря демонстрирует постоянное время O (1) производительность. < /P>
bend_dict_foo1 < /td> 806.9 Us < /td> 9,93 США < /td> 9.29 Us < /td> 183.5938 < /td> 2,29 мб < /td> < /tr>
bend_dict_foo5 < /td> 806.8 Us < /td> 4.72 US < /td> 4.42 Us < /td> 183.5938 < /td> 2,29 мб < /td> < /tr>
bend_dict_foo9 < /td> 793.4 Us < /td> 5.30 Us < /td> 4.70 us < /td> 183.5938 < /td> 2,29 мб
< P> Реализация Switch демонстрирует линейную производительность O (n). Как видите, корпус переключения быстрее, если количество типов составляет около 5 или менее. >