Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.
Например, ниже - класс ученика, который будет использовать его в нашем коде.
public class Student {
private int id;
public int getId() {
return this.id;
}
public setId(int newId) {
this.id = newId;
}
}
Приведенный ниже код дает вам исключение с нулевым указателем.
public class School {
Student obj_Student;
public School() {
try {
obj_Student.getId();
}
catch(Exception e) {
System.out.println("Null Pointer ");
}
}
}
Поскольку вы используете Obj_Student
, но вы забыли инициализировать его, как в правильном коде, показанном ниже:
public class School {
Student obj_Student;
public School() {
try {
obj_Student = new Student();
obj_Student.setId(12);
obj_Student.getId();
}
catch(Exception e) {
System.out.println("Null Pointer ");
}
}
}
Я думаю, что показал Вам этого прежде, но мне нравится забава здесь - это взяло некоторую отладку для разыскивания! (исходный код был, очевидно, более сложным и тонким...)
static void Foo<T>() where T : new()
{
T t = new T();
Console.WriteLine(t.ToString()); // works fine
Console.WriteLine(t.GetHashCode()); // works fine
Console.WriteLine(t.Equals(t)); // works fine
// so it looks like an object and smells like an object...
// but this throws a NullReferenceException...
Console.WriteLine(t.GetType());
}
Поэтому, каков был T...
Ответ: любой Nullable<T>
- такой как int?
. Все методы переопределяются, кроме GetType (), который не может быть; таким образом, это брошено (упакованное) для возражения (и следовательно к пустому указателю) для вызова объекта. GetType ()..., который обращается к пустому указателю; <час>-p
Обновление: график утолщает... Ayende Rahien бросил вниз подобная проблема на его блоге , но с where T : class, new()
:
private static void Main() {
CanThisHappen<MyFunnyType>();
}
public static void CanThisHappen<T>() where T : class, new() {
var instance = new T(); // new() on a ref-type; should be non-null, then
Debug.Assert(instance != null, "How did we break the CLR?");
}
, Но это может быть побеждено! Используя ту же косвенность, используемую вещами как дистанционная работа; при предупреждении - следующее чистое зло :
class MyFunnyProxyAttribute : ProxyAttribute {
public override MarshalByRefObject CreateInstance(Type serverType) {
return null;
}
}
[MyFunnyProxy]
class MyFunnyType : ContextBoundObject { }
С этим на месте, эти new()
вызов перенаправляется к прокси (MyFunnyProxyAttribute
), который возвращается null
. Теперь пойдите и промойте глаза!
Я прибываю немного поздно в сторону, но я имею <ударяют> три забастовка> <забастовка> четыре забастовка> пять:
при опросе InvokeRequired на управлении, которое не было загружено/показано, это скажет ложь - и аварийно завершится в поверхности, при попытке изменить его от другого потока (, решение состоит в том, чтобы сослаться на это. Дескриптор в создателе управления).
Другой, который сбил меня с толку, является этим, учитывая блок с:
enum MyEnum
{
Red,
Blue,
}
, если Вы вычисляете MyEnum. Красный. ToString () в другом блоке, и промежуточные времена кто-то перекомпилировал Ваше перечисление к:
enum MyEnum
{
Black,
Red,
Blue,
}
во времени выполнения, Вы станете "Черными".
у меня была совместно используемая сборка с некоторыми удобными константами в. Мой предшественник оставил загрузку ужасно выглядящих свойств только добирания, я думал, что буду избавляться от помехи и просто использовать общедоступную константу. Я был больше, чем немного удивлен, когда VS скомпилировал их в их значения, и не ссылки.
, Если Вы реализуете новый метод интерфейса от другого блока, но Вы восстанавливаете ссылку на старую версию того блока, Вы получаете TypeLoadException (никакая реализация 'NewMethod'), даже при том, что Вы имеете , реализовал его (см. здесь ).
Dictionary<>: "Порядок, в котором возвращаются объекты, не определен". Это ужасно , потому что это может иногда кусать Вас, но работать другие, и если Вы только что вслепую предположили, что Словарь собирается играть по правилам ("почему не был должен он? Я думал, Список делает"), у Вас действительно должен быть нос в нем, прежде чем Вы наконец начнете подвергать сомнению свое предположение.
, Когда булевская переменная не является ни Верной, ни Ложной?
Bill обнаружил, что можно взломать булевскую переменную так, чтобы, если A Верен и B был Правда, (A и B) Ложь.
Вот пример того, как можно создать структуру, которая вызывает сообщение об ошибке, "Предпринятое для чтения или защищенная от записи память. Это часто - признак, что другая память повреждена". Различие между успехом и отказом является очень тонким.
следующий модульный тест демонстрирует проблему.
Видят, можно ли разработать то, что пошло не так, как надо.
[Test]
public void Test()
{
var bar = new MyClass
{
Foo = 500
};
bar.Foo += 500;
Assert.That(bar.Foo.Value.Amount, Is.EqualTo(1000));
}
private class MyClass
{
public MyStruct? Foo { get; set; }
}
private struct MyStruct
{
public decimal Amount { get; private set; }
public MyStruct(decimal amount) : this()
{
Amount = amount;
}
public static MyStruct operator +(MyStruct x, MyStruct y)
{
return new MyStruct(x.Amount + y.Amount);
}
public static MyStruct operator +(MyStruct x, decimal y)
{
return new MyStruct(x.Amount + y);
}
public static implicit operator MyStruct(int value)
{
return new MyStruct(value);
}
public static implicit operator MyStruct(decimal value)
{
return new MyStruct(value);
}
}
C# поддерживает преобразования между массивами и списками, пока массивы не многомерны и существует отношение наследования между типами, и типы являются ссылочными типами
object[] oArray = new string[] { "one", "two", "three" };
string[] sArray = (string[])oArray;
// Also works for IList (and IEnumerable, ICollection)
IList<string> sList = (IList<string>)oArray;
IList<object> oList = new string[] { "one", "two", "three" };
Примечание, что это не работает:
object[] oArray2 = new int[] { 1, 2, 3 }; // Error: Cannot implicitly convert type 'int[]' to 'object[]'
int[] iArray = (int[])oArray2; // Error: Cannot convert type 'object[]' to 'int[]'
Интересный - когда я сначала посмотрел на это, я предположил, что это было что-то, что компилятор C# проверял на, но даже если Вы испускаете IL непосредственно для удаления шанса интерференции, это все еще происходит, что означает, что это действительно newobj
код операции, это делает проверку.
var method = new DynamicMethod("Test", null, null);
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));
il.Emit(OpCodes.Call, typeof(object).GetMethod("ReferenceEquals"));
il.Emit(OpCodes.Box, typeof(bool));
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }));
il.Emit(OpCodes.Ret);
method.Invoke(null, null);
Это также приравнивается к true
, если Вы проверяете по string.Empty
, что означает, что этот код операции должен иметь специальное поведение интернировать пустые строки.
Public Class Item
Public ID As Guid
Public Text As String
Public Sub New(ByVal id As Guid, ByVal name As String)
Me.ID = id
Me.Text = name
End Sub
End Class
Public Sub Load(sender As Object, e As EventArgs) Handles Me.Load
Dim box As New ComboBox
Me.Controls.Add(box) 'Sorry I forgot this line the first time.'
Dim h As IntPtr = box.Handle 'Im not sure you need this but you might.'
Try
box.Items.Add(New Item(Guid.Empty, Nothing))
Catch ex As Exception
MsgBox(ex.ToString())
End Try
End Sub
вывод "Предпринят для чтения защищенной памяти. Это - признак, что другая память повреждена".
Что эта функция сделает, если названо как Rec(0)
(не под отладчиком)?
static void Rec(int i)
{
Console.WriteLine(i);
if (i < int.MaxValue)
{
Rec(i + 1);
}
}
Ответ:
, который Это вызвано тем, что 64-разрядный JIT-компилятор применяет оптимизацию последнего вызова , тогда как 32-разрядный JIT не делает.
, К сожалению, у меня нет 64-разрядной машины для вручения для проверки этого, но метод действительно удовлетворяет всем условиям для оптимизации последнего вызова. Если бы у кого-либо действительно есть тот, мне было бы интересно видеть, верно ли это.
Округление банкиров.
Этот не так ошибка компилятора или неправильное функционирование, но конечно странный угловой случай...
.Net Платформа использует схему или округление известного как Округление банкира.
В Округлении банкиров этих 0,5 чисел округлены к самому близкому четному числу, таким образом
Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...
Это может привести к некоторым неожиданным ошибкам в финансовых вычислениях на основе более известного округления Round-Half-Up.
Это также верно для Visual Basic.
Несколько лет назад, когда мы работали над программой лояльности, у нас возникла проблема с количеством начисляемых клиентам баллов. Проблема была связана с преобразованием типа double в int.
В приведенном ниже коде:
double d = 13.6;
int i1 = Convert.ToInt32(d);
int i2 = (int)d;
выполняет ли i1 == i2 ?
Оказывается, i1! = I2. Из-за различных политик округления в операторе Convert и cast фактические значения следующие:
i1 == 14
i2 == 13
Всегда лучше вызывать Math.Ceiling () или Math.Floor () (или Math.Round с MidpointRounding, что соответствует нашим требованиям)
int i1 = Convert.ToInt32( Math.Ceiling(d) );
int i2 = (int) Math.Ceiling(d);
Они должны были сделать 0 целым числом, даже если есть перегрузка функции enum.
Я знал, что основная команда разработчиков C # обосновывает отображение 0 в enum, но, тем не менее, это не так ортогонально. должно быть. Пример из Npgsql .
Пример теста:
namespace Craft
{
enum Symbol { Alpha = 1, Beta = 2, Gamma = 3, Delta = 4 };
class Mate
{
static void Main(string[] args)
{
JustTest(Symbol.Alpha); // enum
JustTest(0); // why enum
JustTest((int)0); // why still enum
int i = 0;
JustTest(Convert.ToInt32(0)); // have to use Convert.ToInt32 to convince the compiler to make the call site use the object version
JustTest(i); // it's ok from down here and below
JustTest(1);
JustTest("string");
JustTest(Guid.NewGuid());
JustTest(new DataTable());
Console.ReadLine();
}
static void JustTest(Symbol a)
{
Console.WriteLine("Enum");
}
static void JustTest(object o)
{
Console.WriteLine("Object");
}
}
}
Область видимости в C # временами действительно странная. Приведу один пример:
if (true)
{
OleDbCommand command = SQLServer.CreateCommand();
}
OleDbCommand command = SQLServer.CreateCommand();
Не удалось скомпилировать, потому что команда повторно объявлена? Есть некоторые интересные предположения относительно того, почему это работает таким образом в этом потоке в stackoverflow и в моем блоге .
Насколько я знаю, не из коробки. WPF основан на DirectX, но поскольку WPF также поддерживается в Windows XP, он основан на DirectX 9.
Я знаю, что можно использовать DirectX 10 с WPF, но тогда ваше приложение не сможет работать в XP. .
Есть библиотека для WPF под названием Bling, которая поддерживает DirectX 10 (в Vista и Windows 7), которая может вас заинтересовать. Вы можете найти его здесь . Я не знаю, насколько он зрелый.
Кроме того, я наткнулся на этот блог (в основном на французском), в котором говорится об использовании DirectX 10 с WPF.
Наконец, на CodeProject
есть хорошее введение в использование D3DImage с DirectX . Я знаю, что это не совсем ответ на ваш вопрос, но я решил поделиться им с вами в любом случае. Удачи.
затем: Кто сказал, что вы не можете создать экземпляр интерфейса?Это один из самых необычных файлов, которые я когда-либо видел (не считая те, которые здесь, конечно!):
public class Turtle<T> where T : Turtle<T>
{
}
Он позволяет вам объявить его, но не имеет реального использования, поскольку он всегда будет просить вас обернуть любой класс, который вы поместите в центр, с другой черепахой.
[шутка] Полагаю, это черепахи ... [/ joke]
Я нашел второй действительно странный угловой вариант, который намного превосходит мой первый.
Метод String.Equals (String, String, StringComparison) на самом деле не свободен от побочных эффектов.
Я работал над блоком кода, в котором это было в отдельной строке в верхней части некоторой функции:
stringvariable1.Equals(stringvariable2, StringComparison.InvariantCultureIgnoreCase);
Удаление этой строки привело к переполнению стека где-то еще в программе.
Код оказался неверным. установить обработчик того, что по сути было событием BeforeAssemblyLoad, и попытаться выполнить
if (assemblyfilename.EndsWith("someparticular.dll", StringComparison.InvariantCultureIgnoreCase))
{
assemblyfilename = "someparticular_modified.dll";
}
К настоящему времени мне не нужно было вам рассказывать. Использование языка и региональных параметров, который ранее не использовался при сравнении строк, вызывает сборку нагрузки. InvariantCulture не является исключением.
VB.NET, значения NULL и тернарный оператор:
Dim i As Integer? = If(True, Nothing, 5)
На отладку у меня ушло некоторое время, так как я ожидал, что i
не будет содержать ничего
.
Что я на самом деле содержит? 0
.
Это удивительное, но на самом деле «правильное» поведение: Ничто
в VB.NET не совсем то же самое, что null
в CLR: ] Ничто
не может означать null
или значение по умолчанию (T)
для типа значения T
, в зависимости от контекста. В приведенном выше случае If
выводит Integer
как общий тип Nothing
и 5
, поэтому в этом случае Ничто
не означает 0
.
PropertyInfo .SetValue () может присваивать целые числа перечислениям, целые числа - целым значениям, допускающим значение NULL, перечисления - перечислениям, допускающим значение NULL, но не целым числам перечислениям, допускающим значение NULL.
enumProperty.SetValue(obj, 1, null); //works
nullableIntProperty.SetValue(obj, 1, null); //works
nullableEnumProperty.SetValue(obj, MyEnum.Foo, null); //works
nullableEnumProperty.SetValue(obj, 1, null); // throws an exception !!!
Полное описание здесь
Это тот, который я люблю спрашивать на вечеринках (вероятно, поэтому меня больше не приглашают):
Можете ли вы скомпилировать следующий фрагмент кода?
public void Foo()
{
this = new Teaser();
}
Простым читом может быть:
string cheat = @"
public void Foo()
{
this = new Teaser();
}
";
Но настоящее решение таково:
public struct Teaser
{
public void Foo()
{
this = new Teaser();
}
}
Итак, малоизвестный факт, что типы значений (структуры) могут переназначать свои эта
переменная.
Следующее может быть общим знанием, которого мне просто не хватало, но эх. Некоторое время назад у нас был случай с ошибкой, который касался виртуальных свойств. Немного абстрагируясь от контекста, рассмотрите следующий код и примените точку останова к указанной области:
class Program
{
static void Main(string[] args)
{
Derived d = new Derived();
d.Property = "AWESOME";
}
}
class Base
{
string _baseProp;
public virtual string Property
{
get
{
return "BASE_" + _baseProp;
}
set
{
_baseProp = value;
//do work with the base property which might
//not be exposed to derived types
//here
Console.Out.WriteLine("_baseProp is BASE_" + value.ToString());
}
}
}
class Derived : Base
{
string _prop;
public override string Property
{
get { return _prop; }
set
{
_prop = value;
base.Property = value;
} //<- put a breakpoint here then mouse over BaseProperty,
// and then mouse over the base.Property call inside it.
}
public string BaseProperty { get { return base.Property; } private set { } }
}
Находясь в контексте объекта Derived
, вы можете получить такое же поведение при добавлении base.Property
] как часы или набрав base.Property
в Quickwatch.
Мне потребовалось время, чтобы понять, что происходит. В конце концов, Quickwatch меня просветил. При входе в Quickwatch и исследовании объекта d Производный
(или из контекста объекта, this
) и выборе поля base
, поле редактирования наверху Quickwatch отображает следующее приведение:
((TestProject1.Base)(d))
Это означает, что если base заменяется как таковая, вызов будет
public string BaseProperty { get { return ((TestProject1.Base)(d)).Property; } private set { } }
для Watch, Quickwatch и всплывающих подсказок при наведении курсора мыши, и тогда будет иметь смысл для его отображения «УДИВИТЕЛЬНЫЙ»
вместо «BASE_AWESOME»
при рассмотрении полиморфизма. Я до сих пор не уверен, почему это преобразовало бы его в приведение, одна из гипотез состоит в том, что call
может быть недоступен из контекста этих модулей, а только callvirt
.
В любом случае, это явно ничего не меняет с точки зрения функциональности, Derived.BaseProperty
по-прежнему действительно возвращает «BASE_AWESOME»
, и, таким образом, это не было корнем нашей ошибки. на работе просто сбивающий с толку компонент.Однако мне показалось интересным, как это могло ввести в заблуждение разработчиков, которые не знали об этом факте во время сеансов отладки, особенно если Base
не отображается в вашем проекте, а упоминается как сторонняя DLL, в результате чего разработчики просто говорю:
«Эй, подожди ... что? Боже, эта DLL похожа, .. делает что-то забавное»
Я не уверен, что это Windows Vista / 7 или странность .Net, но я некоторое время почесал в затылке.
string filename = @"c:\program files\my folder\test.txt";
System.IO.File.WriteAllText(filename, "Hello world.");
bool exists = System.IO.File.Exists(filename); // returns true;
string text = System.IO.File.ReadAllText(filename); // Returns "Hello world."
В Windows Vista / 7 файл будет фактически записан в C: \ Users \ <имя пользователя> \ Virtual Store \ Program Files \ my folder \ test.txt
Это самое странное, с которым я столкнулся случайно:
public class DummyObject
{
public override string ToString()
{
return null;
}
}
Используется следующим образом:
DummyObject obj = new DummyObject();
Console.WriteLine("The text: " + obj.GetType() + " is " + obj);
Выдает исключение NullReferenceException
. Оказывается, несколько добавлений компилируются компилятором C # для вызова String.Concat (объект [])
. До .NET 4 была ошибка только в той перегрузке Concat, когда объект проверялся на null, но не на результат ToString ():
object obj2 = args[i];
string text = (obj2 != null) ? obj2.ToString() : string.Empty;
// if obj2 is non-null, but obj2.ToString() returns null, then text==null
int length = text.Length;
Это ошибка ECMA-334 §14.7.4:
Двоичный оператор + выполняет конкатенацию строк, когда один или оба операнда имеют тип
строка
. Если операнд конкатенации строк равенnull
, подставляется пустая строка. В противном случае любой нестроковый операнд преобразуется в его строковое представление путем вызова виртуального методаToString
, унаследованного от объекта типа. Если
ToString
возвращаетnull
, подставляется пустая строка.
Есть кое-что действительно интересное в C# - то, как он работает с закрытиями.
Вместо того, чтобы копировать значения стековой переменной в свободную от замыкания переменную, он делает эту магию препроцессора, оборачивая все появления переменной в объект, и таким образом перемещает ее из стека - прямо в кучу! :)
Я думаю, это делает C# даже более функционально полным (или лямбда-полным, а)) языком, чем сам ML (который использует копирование значений стека AFAIK). F# тоже имеет эту возможность, как и C#.
Это действительно приносит мне много радости, спасибо вам, ребята из MS!
Это не странность или угловой случай... но что-то действительно неожиданное для VM-языка, основанного на стеке :)
Из вопроса, который я задал не так давно:
Условный оператор не может неявно приводить?
Дано:
Bool aBoolValue;
Где aBoolValue
присваивается True или False;
Следующее будет не компилировать:
Byte aByteValue = aBoolValue ? 1 : 0;
Но это будет:
Int anIntValue = aBoolValue ? 1 : 0;
Полученный ответ тоже довольно хорош.
Вы когда-нибудь думали, что компилятор C # может сгенерировать недопустимый CIL? Запустите это, и вы получите TypeLoadException
:
interface I<T> {
T M(T p);
}
abstract class A<T> : I<T> {
public abstract T M(T p);
}
abstract class B<T> : A<T>, I<int> {
public override T M(T p) { return p; }
public int M(int p) { return p * 2; }
}
class C : B<int> { }
class Program {
static void Main(string[] args) {
Console.WriteLine(new C().M(42));
}
}
Я не знаю, как это работает в компиляторе C # 4.0.
ИЗМЕНИТЬ : это результат моей системы:
C:\Temp>type Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1 {
interface I<T> {
T M(T p);
}
abstract class A<T> : I<T> {
public abstract T M(T p);
}
abstract class B<T> : A<T>, I<int> {
public override T M(T p) { return p; }
public int M(int p) { return p * 2; }
}
class C : B<int> { }
class Program {
static void Main(string[] args) {
Console.WriteLine(new C().M(11));
}
}
}
C:\Temp>csc Program.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.1
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.
C:\Temp>Program
Unhandled Exception: System.TypeLoadException: Could not load type 'ConsoleAppli
cation1.C' from assembly 'Program, Version=0.0.0.0, Culture=neutral, PublicKeyTo
ken=null'.
at ConsoleApplication1.Program.Main(String[] args)
C:\Temp>peverify Program.exe
Microsoft (R) .NET Framework PE Verifier. Version 3.5.30729.1
Copyright (c) Microsoft Corporation. All rights reserved.
[token 0x02000005] Type load failed.
[IL]: Error: [C:\Temp\Program.exe : ConsoleApplication1.Program::Main][offset 0x
00000001] Unable to resolve token.
2 Error(s) Verifying Program.exe
C:\Temp>ver
Microsoft Windows XP [Version 5.1.2600]
Что если у вас есть общий класс, у которого есть методы, которые могут быть неоднозначными в зависимости от аргументов типа? Недавно я столкнулся с этой ситуацией при написании двустороннего словаря. Я хотел написать симметричные методы Get()
, которые возвращали бы противоположный аргумент. Что-то вроде этого:
class TwoWayRelationship<T1, T2>
{
public T2 Get(T1 key) { /* ... */ }
public T1 Get(T2 key) { /* ... */ }
}
Все хорошо, если вы создадите экземпляр, где T1
и T2
- разные типы:
var r1 = new TwoWayRelationship<int, string>();
r1.Get(1);
r1.Get("a");
Но если T1
и T2
- одинаковые (и, вероятно, если один был подклассом другого), то это ошибка компилятора:
var r2 = new TwoWayRelationship<int, int>();
r2.Get(1); // "The call is ambiguous..."
Интересно, что все остальные методы во втором случае остаются пригодными для использования; только вызов теперь уже однозначного метода вызывает ошибку компилятора. Интересный случай, хотя немного маловероятный и неясный.
В используемом нами API методы, возвращающие объект домена, могут возвращать специальный «нулевой объект». В реализации этого оператор сравнения и метод Equals ()
переопределяются для возврата true
, если он сравнивается с null
.
Таким образом, у пользователя этого API может быть какой-то код вроде этого:
return test != null ? test : GetDefault();
или, возможно, более подробный, например:
if (test == null)
return GetDefault();
return test;
где GetDefault ()
- это метод, возвращающий какое-то значение по умолчанию, которое мы хотим использовать вместо null
. Меня поразило удивление, когда я использовал ReSharper и, следуя его рекомендации, переписал любое из этого на следующее:
return test ?? GetDefault();
Если тестовый объект является нулевым объектом, возвращенным из API, вместо правильного null
, поведение кода теперь изменилось, поскольку оператор объединения с нулевым значением фактически проверяет наличие null
, а не работает operator =
или Equals ()
.
Следующий производный класс обращается к частному полю из своего базового класса, и компилятор молча смотрит на другую сторону:
public class Derived : Base
{
public int BrokenAccess()
{
return base.m_basePrivateField;
}
}
Это действительно частное поле:
private int m_basePrivateField = 0;
Угадайте, как можно скомпилировать такой код?
.
.
.
.
.
.
.
Уловка состоит в том, чтобы объявить Derived
внутренним классом Base
:
public class Base
{
private int m_basePrivateField = 0;
public class Derived : Base
{
public int BrokenAccess()
{
return base.m_basePrivateField;
}
}
}
Внутренним классам предоставляется полный доступ к внешним членам класса. В этом случае внутренний класс также является производным от внешнего класса. Это позволяет нам «нарушить» инкапсуляцию закрытых членов.
Следующая Ложь печати вместо того, чтобы выдать исключение переполнения:
Console.WriteLine("{0}", yep(int.MaxValue ));
private bool yep( int val )
{
return ( 0 < val * 2);
}
У этого был я действительно озадаченный (я приношу извинения за длину, но это - WinForm). Я отправил его в эти группы новостей некоторое время назад.
я столкнулся с интересной ошибкой. У меня есть обходные решения, но я хотел бы знать корень проблемы. Я разделил его вниз в короткий файл и надеюсь, что у кого-то могла бы быть идея о том, что продолжается.
Это - простая программа, которая загружает управление на форму и связывает "Нечто" против поля комбинированного списка ("SelectedItem"), поскольку это - свойство "Bar" и datetimepicker ("Значение"), поскольку это - свойство "DateTime". DateTimePicker. Видимое значение имеет значение false. Как только это загружается, выберите поле комбинированного списка и затем попытайтесь отменить выбор его путем установки флажка. Это представляется невозможное полем комбинированного списка, сохраняющим фокус, Вы не можете даже закрыть форму, такой, это - схватывание на фокусе.
я нашел три способа решить эту проблему.
a) Удаляют привязку к Панели (немного очевидной)
, b) Удаляют привязку к DateTime
c), Делают DateTimePicker видимым!?!
я в настоящее время выполняю Win2k. И.NET 2.00, я думаю 1.1, имеет ту же проблему. Код ниже.
using System;
using System.Collections;
using System.Windows.Forms;
namespace WindowsApplication6
{
public class Bar
{
public Bar()
{
}
}
public class Foo
{
private Bar m_Bar = new Bar();
private DateTime m_DateTime = DateTime.Now;
public Foo()
{
}
public Bar Bar
{
get
{
return m_Bar;
}
set
{
m_Bar = value;
}
}
public DateTime DateTime
{
get
{
return m_DateTime;
}
set
{
m_DateTime = value;
}
}
}
public class TestBugControl : UserControl
{
public TestBugControl()
{
InitializeComponent();
}
public void InitializeData(IList types)
{
this.cBoxType.DataSource = types;
}
public void BindFoo(Foo foo)
{
this.cBoxType.DataBindings.Add("SelectedItem", foo, "Bar");
this.dtStart.DataBindings.Add("Value", foo, "DateTime");
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.checkBox1 = new System.Windows.Forms.CheckBox();
this.cBoxType = new System.Windows.Forms.ComboBox();
this.dtStart = new System.Windows.Forms.DateTimePicker();
this.SuspendLayout();
//
// checkBox1
//
this.checkBox1.AutoSize = true;
this.checkBox1.Location = new System.Drawing.Point(14, 5);
this.checkBox1.Name = "checkBox1";
this.checkBox1.Size = new System.Drawing.Size(97, 20);
this.checkBox1.TabIndex = 0;
this.checkBox1.Text = "checkBox1";
this.checkBox1.UseVisualStyleBackColor = true;
//
// cBoxType
//
this.cBoxType.FormattingEnabled = true;
this.cBoxType.Location = new System.Drawing.Point(117, 3);
this.cBoxType.Name = "cBoxType";
this.cBoxType.Size = new System.Drawing.Size(165, 24);
this.cBoxType.TabIndex = 1;
//
// dtStart
//
this.dtStart.Location = new System.Drawing.Point(117, 40);
this.dtStart.Name = "dtStart";
this.dtStart.Size = new System.Drawing.Size(165, 23);
this.dtStart.TabIndex = 2;
this.dtStart.Visible = false;
//
// TestBugControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.dtStart);
this.Controls.Add(this.cBoxType);
this.Controls.Add(this.checkBox1);
this.Font = new System.Drawing.Font("Verdana", 9.75F,
System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point,
((byte)(0)));
this.Margin = new System.Windows.Forms.Padding(4);
this.Name = "TestBugControl";
this.Size = new System.Drawing.Size(285, 66);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.CheckBox checkBox1;
private System.Windows.Forms.ComboBox cBoxType;
private System.Windows.Forms.DateTimePicker dtStart;
}
public class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
}
void Form1_Load(object sender, EventArgs e)
{
InitializeControl();
}
public void InitializeControl()
{
TestBugControl control = new TestBugControl();
IList list = new ArrayList();
for (int i = 0; i < 10; i++)
{
list.Add(new Bar());
}
control.InitializeData(list);
control.BindFoo(new Foo());
this.Controls.Add(control);
}
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Text = "Form1";
}
#endregion
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
Я думаю, что ответ на вопрос - то, потому что .net использует строку, интернирующую что-то, что могло бы заставить равные строки указывать на тот же объект (так как строки изменяемы, это не проблема)
(я не говорю о переопределенном операторе равенства на строковом классе)