Здравствуйте, _FRED_, Вы писали:
_FR>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
Мое мнение — копипэйст со статического Equals, где эта проверка осмыслена (ибо Equals(null, null) == true)
С уважением, Евгений
JetBrains, Inc. "Develop with pleasure!"
Здравствуйте, xvost, Вы писали:
_FR>>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
X>Мое мнение — копипэйст со статического Equals, где эта проверка осмыслена (ибо Equals(null, null) == true)
Да как-то совсем не похоже на
// Determines whether two Strings match.public static bool Equals(String a, String b) {
if ((Object)a==(Object)b) {
return true;
}
if ((Object)a==null || (Object)b==null) {
return false;
}
return EqualsHelper(a, b);
}
В общем, если действительно глупость, то всё ясно и не интересно.
... << RSDN@Home 1 alpha 3 rev. 0>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>>>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" :???: Индусы? "Наследие" C++? :maniac:
учитывая ситуацию, когда строки пытаются максимально подражать value типам такая проверка может выглядеть достаточно осмысленно. кроме того, всегда есть возможность вызвать string.Equals передав null в качестве this
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Здравствуйте, _FRED_, Вы писали:
_FR>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
using System;
class A
{
public virtual void Foo()
{
Console.WriteLine(this == null);
}
static void Main()
{
((Action) Delegate.CreateDelegate(typeof(Action), null, ((Action) new A().Foo).Method))();
}
}
Здравствуйте, TK, Вы писали:
_FR>>>>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
TK>учитывая ситуацию, когда строки пытаются максимально подражать value типам такая проверка может выглядеть достаточно осмысленно.
То есть проверка value-типа на null выглядит осмысленно?
TK>кроме того, всегда есть возможность вызвать string.Equals передав null в качестве this
В смысле статический String.Equals(string, string)? Или на IL вызвать экземплярный Equals(string), передав в this пустой указатель? Пускай даже так
Здравствуйте, nikov, Вы писали:
_FR>>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
N> ((Action) Delegate.CreateDelegate(typeof(Action), null, ((Action) new A().Foo).Method))();
Круть virtual даже не нужным оказалось.
... << RSDN@Home 1 alpha 3 rev. 0>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Смотрю исходники System.String ("\redbits\ndp\clr\src\BCL\System\String.cs") _FR>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
Инструкция callvirt используется для вызова всех (в том числе и невиртуальных) методов для многих языков, но не для всех. Именно она гарантирует this != null. В каком-нибудь языке компилятор мог бы определить, что данный тип суть sealed и Equals всегда будет использоваться известный, и в результате генерировать call, который не проверяется в момент вызова. Возможно, для строчек существует такая оптимизация в FCL, CLR или в каком-то другом месте, известном Microsoft.
Может, однако, быть и такое, что C#-компилятор когда-то на заре своей юности генерировал callvirt не во всех случаях, а в строчках просто завалялась проверочка
В любом случае, я сомневаюсь, что рассмотренный Nikov вариант является чем-то, для чего MS будет вставлять специальную проверку
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, _FRED_, Вы писали:
_FR>>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
N>
Здравствуйте, _FRED_, Вы писали:
_FR>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
using namespace System;
ref class Test
{
public:
void Foo()
{
if (this == nullptr)
Console::WriteLine(L"Hello, Lucky World");
}
};
int main(array<System::String ^> ^args)
{
Test^ test = nullptr;
test->Foo();
return 0;
}
Здравствуйте, orangy, Вы писали:
_FR>>Смотрю исходники System.String ("\redbits\ndp\clr\src\BCL\System\String.cs") _FR>>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
O>Инструкция callvirt используется для вызова всех (в том числе и невиртуальных) методов для многих языков, но не для всех. Именно она гарантирует this != null.
OK
O>В каком-нибудь языке компилятор мог бы определить, что данный тип суть sealed и Equals всегда будет использоваться известный, и в результате генерировать call, который не проверяется в момент вызова.
OK, но правильно ли я понимаю, что выполнение условия "this == null" в таком случае будет означать ошибку в компиляторе, так как далее по коду есть обращения к this? Или нормальный, работающий компилятор мог бы "в некоторых случаях" законно вызвать метод, обращающийся к полям объекта так, что ссылка на this внутри метода будет пустая?
O>Может, однако, быть и такое, что C#-компилятор когда-то на заре своей юности генерировал callvirt не во всех случаях, а в строчках просто завалялась проверочка
Так это проверка, получается, от кривого компилятора? Я просто не понимаю, для чего эта провера в нормальном режиме работы? Примеры nikov-а и desco хоть и законны, но не должны обязывать защищаться от них.
O>В любом случае, я сомневаюсь, что рассмотренный Nikov вариант является чем-то, для чего MS будет вставлять специальную проверку
... << RSDN@Home 1 alpha 3 rev. 0>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, orangy, Вы писали:
O>В любом случае, я сомневаюсь, что рассмотренный Nikov вариант является чем-то, для чего MS будет вставлять специальную проверку
Ну это всего лишь иллюстрация того, что там может быть null, на удобном мне языке. То же самое, но без рефлекшна, можно сделать на ILASM или C++/CLI. Видимо, приведенный в начале код писался в расчете на взаимодействие с другими языками.
Здравствуйте, nikov, Вы писали:
N>Ну это всего лишь иллюстрация того, что там может быть null, на удобном мне языке. То же самое, но без рефлекшна, можно сделать на ILASM или C++/CLI. Видимо, приведенный в начале код писался в расчете на взаимодействие с другими языками.
Хм, ... если исходить из такой логики, то тогда надо в начале каждого метода ставить такую проверку, т.к. используя особенности языков можно добиться ситуации this == null. Иначе библиотека "не расчитана на другие языки". Так что ли?
По мне так это _очень_ странная логика. Т.к. нигде, насколько я знаю, не оговоренно, что this может быть null в .NET языках.
Здравствуйте, AngeL B., Вы писали:
AB>Т.к. нигде, насколько я знаю, не оговоренно, что this может быть null в .NET языках.
Оговорено. Ecma-335, Partition I, 8.4.2 Methods:
An instance method is invoked by specifying a class and the instance method within that class. The
object passed as this can be null (a special value indicating that no instance is being specified) or an instance of
any type that inherits (see §8.9.8) from the class that defines the method.
N>An instance method is invoked by specifying a class and the instance method within that class. The
N>object passed as this can be null (a special value indicating that no instance is being specified) or an instance of
N>any type that inherits (see §8.9.8) from the class that defines the method.
1) Спасибо!
2) Ой-ой-ой как все запущено. Тогда у меня возникает другой не менее интересный вопрос. А зачем такая возможность была оговорена в стандарте? Какой смысл в instance-методе при this == null? Только для того чтобы иметь возможность не делать такую проверку перед вызовом и иметь при этом осмысленно выполняемый код?
Ведь стандарт просто так с потолка не пишут. И если там это есть, то должны были быть достаточно сильные аргументы.
Здравствуйте, AngeL B., Вы писали:
AB>А зачем такая возможность была оговорена в стандарте? Какой смысл в instance-методе при this == null? AB>Ведь стандарт просто так с потолка не пишут. И если там это есть, то должны были быть достаточно сильные аргументы.
Кстати, в C# 3.0 есть способ загнать null в this без использования рефлекшна, но по-моему это баг:
using System;
using System.Linq.Expressions;
class A
{
static void Main()
{
Expression<Action<A>> e = x => new Action(x.Foo)();
e.Compile()(null);
}
void Foo()
{
Console.WriteLine(this == null);
}
}
Здравствуйте, AndrewVK, Вы писали:
N>>Кстати, в C# 3.0 есть способ загнать null в this без использования рефлекшна
AVK>Как это без использования? Expression внутри содержит всякие MethodInfo, да и DynamicMethod это тоже рефлекшен.
Да, согласен. Хотел написать "без явного использования".
Как бы оно там внутри не было реализовано, оно не должно нарушать правила языка. Кстати, вот несколько интересных багов с expression trees, которые проявляются в SP1 Beta, и которые так и не успевают исправить в SP1.
1)
// Debug configuration only!using System;
using System.Linq.Expressions;
class A
{
public static bool operator true(A x)
{
return true;
}
public static bool operator false(A x)
{
return false;
}
}
class B : A
{
public static B operator |(B x, B y)
{
return new B();
}
static bool op_True<T>(B x)
{
return true;
}
static bool op_False(B x)
{
return false;
}
static void Main()
{
Expression<Func<B, A>> ex = x => x || x;
ex.Compile()(null);
}
}
2)
using System;
using System.Linq.Expressions;
struct A
{
static void Main()
{
Func<A?, D> f = y => (D)y;
f(null);
Expression<Func<A?, D>> x = y => (D)y;
x.Compile()(null);
}
}
class B
{
public static implicit operator B(A x)
{
return new D();
}
}
class D : B { }
3)
using System;
using System.Linq.Expressions;
abstract class A
{
static void Main()
{
Expression<Func<A, Action>> ex = x => x.Foo;
var a = ex.Compile()(null);
a();
}
public abstract void Foo();
}
Здравствуйте, nikov, Вы писали:
N>Как бы оно там внутри не было реализовано, оно не должно нарушать правила языка.
Рантайма, ты хотел сказать? При помощи динамической компиляции можно нарушать любые правила языка, если они не противоречат рантайму.
N> Кстати, вот несколько интересных багов с expression trees, которые проявляются в SP1 Beta, и которые так и не успевают исправить в SP1.
В SP1 меняют компилятор???
... <<RSDN@Home 1.2.0 alpha 4 rev. 1090 on Windows Vista 6.0.6001.65536>>
Здравствуйте, AndrewVK, Вы писали:
N>>Как бы оно там внутри не было реализовано, оно не должно нарушать правила языка. AVK>Рантайма, ты хотел сказать? При помощи динамической компиляции можно нарушать любые правила языка, если они не противоречат рантайму.
Не понял твою мысль. Тело лямбды, записанной в C#, должно выполняться одинаково, независимо от того, преобразована ли она непосредственно в делегат, или преобразована в expression tree и затем скомпилирована.
AVK>В SP1 меняют компилятор???
Здравствуйте, nikov, Вы писали:
N>Не понял твою мысль. Тело лямбды, записанной в C#, должно выполняться одинаково, независимо от того, преобразована ли она непосредственно в делегат, или преобразована в expression tree и затем скомпилирована.
Это не имеет отношения к языку. Если формирование expression tree еще можно как то к языку привязать, то уж динамическая компиляция — чисто библиотечная фишка.
... <<RSDN@Home 1.2.0 alpha 4 rev. 1090 on Windows Vista 6.0.6001.65536>>
Здравствуйте, AndrewVK, Вы писали:
N>>Не понял твою мысль. Тело лямбды, записанной в C#, должно выполняться одинаково, независимо от того, преобразована ли она непосредственно в делегат, или преобразована в expression tree и затем скомпилирована.
AVK>Это не имеет отношения к языку. Если формирование expression tree еще можно как то к языку привязать, то уж динамическая компиляция — чисто библиотечная фишка.
Я хочу сказать, что компилятор должен формировать expression tree с оглядкой на то, как реализована динамическая компиляция в библиотеке, так чтобы конечный наблюдаемый результат был таким же, как и после преобразования в делегат.
Здравствуйте, nikov, Вы писали:
N>Я хочу сказать, что компилятор должен формировать expression tree с оглядкой на то, как реализована динамическая компиляция в библиотеке
Не согласен. Динамическая компиляция в библиотеке вторична (она, собственно, и появилась в последний момент, перед релизом).
N>, так чтобы конечный наблюдаемый результат был таким же, как и после преобразования в делегат.
Вот и надо подкручивать динамическую компиляцию, чтобы она не позволяла подобных финтов ушами.
... <<RSDN@Home 1.2.0 alpha 4 rev. 1090 on Windows Vista 6.0.6001.65536>>
Здравствуйте, _FRED_, Вы писали:
_FR>Смотрю исходники System.String ("\redbits\ndp\clr\src\BCL\System\String.cs")
_FR>// Determines whether two strings match.
_FR>[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
_FR>public override bool Equals(Object obj) {
_FR> String str = obj as String;
_FR> if (str == null)
_FR> {
_FR> // exception will be thrown later for null this
_FR> if (this != null) return false;
_FR> }
_FR> return EqualsHelper(this, str);
_FR>}
_FR>(то же и с перегруженной версией с параметром типа string) и не понимаю, зачем проверка "this != null" Индусы? "Наследие" C++?
И вот пришёл четвёртый фреймворк (и наступил "later" ):
public override bool Equals(Object obj) {
if (this == null) //this is necessary to guard against reverse-pinvokes and throw new NullReferenceException(); //other callers who do not use the callvirt instruction
Help will always be given at Hogwarts to those who ask for it.