using System;
class A
{
public virtual void Foo(int x = 1)
{
Console.WriteLine("A.Foo({0})", x);
}
}
class B : A
{
public override void Foo(int x = 2)
{
Console.WriteLine("B.Foo({0})", x);
}
static void Main()
{
B b = new B();
b.Foo();
A a = b;
a.Foo();
}
}
похоже, что со значениями optional параметров та же ситуация, что и с именами
For virtual and abstract members, the parameter names in overrides may be different from those in the declaration. For the purposes of overload resolution, the parameter names that apply are the ones that appear in the most specific override of the function member with respect to the static type of the target of the member access.
Здравствуйте, Пельмешко, Вы писали:
П>Кстати, а dynamic бы себя так же повёл?
Как "так же"? Тут все детали влияют на результат.
П>Оно вообще учитывает default arguments?
Да.
Здравствуйте, Пельмешко, Вы писали:
П>Хотя поведение, логическое, конечно...
и в чем ты тут видишь логику?
Поведение кода соответствует классам следующего вида
class A
{
public virtual void Foo(int x)
{
Console.WriteLine("A.Foo({0})", x);
}
[CompileGenerated]public void Foo()
{
Foo(1);
}
}
class B : A
{
public override void Foo(int x)
{
Console.WriteLine("B.Foo({0})", x);
}
[CompileGenerated]public void Foo()
{
Foo(2);
}
}
Ты считаешь, что логично при объявлении виртуального метода с пар-ми по умолчанию, вспомогательные функции делать НЕ виртуальными? Да, если поведение делать виртуальным, то будет еще более странные эффекты, когда значение по умолчанию будет своим для каждого из объектов. Но если из двух сортов сам знаешь чего, одно с ароматизатором фиалки, то это не значит что это уже фиалка.
А правильно было бы так.
Изменение значения параметра по умолчанию — это изменение декларации метода. Следовательно, это уже "override", а "new" метода, со всеми вытекающими.
Здравствуйте, AngeL B., Вы писали:
П>>Хотя поведение, логическое, конечно... AB>и в чем ты тут видишь логику? AB>Поведение кода соответствует классам следующего вида AB>
AB>class A
AB>{
AB> public virtual void Foo(int x)
AB> {
AB> Console.WriteLine("A.Foo({0})", x);
AB> }
AB>[CompileGenerated]
AB> public void Foo()
AB> {
AB> Foo(1);
AB> }
AB>}
AB>
Нету там никаких compiler-generated членов.
Нужные аргументы вставляются в месте вызова.
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, AngeL B., Вы писали:
П>>>Хотя поведение, логическое, конечно... AB>>и в чем ты тут видишь логику? AB>>Поведение кода СООТВЕТСТВУЕТ классам следующего вида
N>Нету там никаких compiler-generated членов. N>Нужные аргументы вставляются в месте вызова.
я не говорил, что там есть CompileGenerated-методы. Я сказал, что код СООТВЕТСТВУЕТ коду классов с CompileGenerated-методами.
То, что ты говоришь тоже понятно. Но от этого еще хуже. И означает, что декларация в классе, позволяет в определенных случаях генерировать код вне класса, что является уже нарушением инкапсуляции.
Похожая (приблизительно) проблема в программировании уже была и была связанна с освобождением стека после вызова функции. Помнишь какой метод освобождения победил и почему?
Здравствуйте, AngeL B., Вы писали:
AB>То, что ты говоришь тоже понятно. Но от этого еще хуже. И означает, что декларация в классе, позволяет в определенных случаях генерировать код вне класса, что является уже нарушением инкапсуляции.
Вообще-то, декларация в классе всегда позволяет генерировать код вне класса. И никаким нарушением инкапсуляции это не является. Именно декларация метода позволяет вообще сгенерировать код вызова этого метода. Независимо от того, есть там default параметры или нет.
AB>Похожая (приблизительно) проблема в программировании уже была и была связанна с освобождением стека после вызова функции. Помнишь какой метод освобождения победил и почему?
Похожая (точно) проблема в программировании уже была и была связана с использованием Enum-констант из другой сборки. Помнишь, какой метод использования победил, и почему?
Ситуация на самом деле крайне проста: на уровне MSIL нет никаких "default parameters". Компилятор обязан вставить какие-то значения в стек для всех аргументов вызова.
Откуда он будет брать эти значения? Вариантов всего два:
1. Статическое связывание. Компилятор в процессе компиляции использует метаданные класса, и зашивает их в место вызова
2. Динамическое связывание. Компилятор перед вызовом вставляет злой код, основанный на reflection, для получения значений default-параметров.
Понятно, почему вариант 2 неприемлем? Как минимум, в качестве стандартного варианта.
Насколько я понимаю, если тебе принципиально нужно использовать именно те значения default параметров, которые применены в фактическом типе this-аргумента, то ты можешь заставить компилятор выполнить динамическое связывание путём применения dynamic.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Насколько я понимаю, если тебе принципиально нужно использовать именно те значения default параметров, которые применены в фактическом типе this-аргумента, то ты можешь заставить компилятор выполнить динамическое связывание путём применения dynamic.
А как кстати вытаскиваются default-параметры при рефлексии?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> А как кстати вытаскиваются default-параметры при рефлексии?
Эти значения лежат в метаданных в специальной таблице и достаются таким образом:
using System;
class A
{
static void Main()
{
Console.WriteLine(typeof(A).GetMethod("Foo").GetParameters()[0].DefaultValue);
}
public static void Foo(int x = 555)
{
}
}
Здравствуйте, nikov, Вы писали: N>Кстати, хотя рефлектор показывает их как custom attributes, но на самом деле это pseudo-custom attributes, как, например Serializable или MethodImpl.
Спасибо интересно.
и солнце б утром не вставало, когда бы не было меня