Каков самый странный угловой случай, который Вы видели в C# или.NET? [закрытый]

Исключение нулевого указателя - это индикатор того, что вы используете объект, не инициализируя его.

Например, ниже - класс ученика, который будет использовать его в нашем коде.

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 ");
        }
    }
}
322
задан 4 revs 4 February 2010 в 12:53
поделиться

32 ответа

Я думаю, что показал Вам этого прежде, но мне нравится забава здесь - это взяло некоторую отладку для разыскивания! (исходный код был, очевидно, более сложным и тонким...)

    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. Теперь пойдите и промойте глаза!

394
ответ дан Marc Gravell 23 November 2019 в 00:56
поделиться

Я прибываю немного поздно в сторону, но я имею <ударяют> три <забастовка> четыре пять:

  1. при опросе InvokeRequired на управлении, которое не было загружено/показано, это скажет ложь - и аварийно завершится в поверхности, при попытке изменить его от другого потока (, решение состоит в том, чтобы сослаться на это. Дескриптор в создателе управления).

  2. Другой, который сбил меня с толку, является этим, учитывая блок с:

    enum MyEnum
    {
        Red,
        Blue,
    }
    

    , если Вы вычисляете MyEnum. Красный. ToString () в другом блоке, и промежуточные времена кто-то перекомпилировал Ваше перечисление к:

    enum MyEnum
    {
        Black,
        Red,
        Blue,
    }
    

    во времени выполнения, Вы станете "Черными".

  3. у меня была совместно используемая сборка с некоторыми удобными константами в. Мой предшественник оставил загрузку ужасно выглядящих свойств только добирания, я думал, что буду избавляться от помехи и просто использовать общедоступную константу. Я был больше, чем немного удивлен, когда VS скомпилировал их в их значения, и не ссылки.

  4. , Если Вы реализуете новый метод интерфейса от другого блока, но Вы восстанавливаете ссылку на старую версию того блока, Вы получаете TypeLoadException (никакая реализация 'NewMethod'), даже при том, что Вы имеете , реализовал его (см. здесь ).

  5. Dictionary<>: "Порядок, в котором возвращаются объекты, не определен". Это ужасно , потому что это может иногда кусать Вас, но работать другие, и если Вы только что вслепую предположили, что Словарь собирается играть по правилам ("почему не был должен он? Я думал, Список делает"), у Вас действительно должен быть нос в нем, прежде чем Вы наконец начнете подвергать сомнению свое предположение.

47
ответ дан Community 23 November 2019 в 00:56
поделиться

, Когда булевская переменная не является ни Верной, ни Ложной?

Bill обнаружил, что можно взломать булевскую переменную так, чтобы, если A Верен и B был Правда, (A и B) Ложь.

Взломанные булевские переменные

56
ответ дан Robert Harvey 23 November 2019 в 00:56
поделиться

Вот пример того, как можно создать структуру, которая вызывает сообщение об ошибке, "Предпринятое для чтения или защищенная от записи память. Это часто - признак, что другая память повреждена". Различие между успехом и отказом является очень тонким.

следующий модульный тест демонстрирует проблему.

Видят, можно ли разработать то, что пошло не так, как надо.

    [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);
        }
    }
20
ответ дан abatishchev 23 November 2019 в 00:56
поделиться

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[]'
18
ответ дан Peter van der Heijden 23 November 2019 в 00:56
поделиться

Интересный - когда я сначала посмотрел на это, я предположил, что это было что-то, что компилятор 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, что означает, что этот код операции должен иметь специальное поведение интернировать пустые строки.

12
ответ дан Greg Beech 23 November 2019 в 00:56
поделиться
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

вывод "Предпринят для чтения защищенной памяти. Это - признак, что другая память повреждена".

10
ответ дан Konrad Rudolph 23 November 2019 в 00:56
поделиться

Что эта функция сделает, если названо как Rec(0) (не под отладчиком)?

static void Rec(int i)
{
    Console.WriteLine(i);
    if (i < int.MaxValue)
    {
        Rec(i + 1);
    }
}

Ответ:

  • На 32-разрядном JIT это должно привести к StackOverflowException
  • На 64-разрядном JIT, это должно распечатать все числа к интервалу. MaxValue

, который Это вызвано тем, что 64-разрядный JIT-компилятор применяет оптимизацию последнего вызова , тогда как 32-разрядный JIT не делает.

, К сожалению, у меня нет 64-разрядной машины для вручения для проверки этого, но метод действительно удовлетворяет всем условиям для оптимизации последнего вызова. Если бы у кого-либо действительно есть тот, мне было бы интересно видеть, верно ли это.

176
ответ дан Greg Beech 23 November 2019 в 00:56
поделиться

Округление банкиров.

Этот не так ошибка компилятора или неправильное функционирование, но конечно странный угловой случай...

.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.

216
ответ дан Matt J 23 November 2019 в 00:56
поделиться

Несколько лет назад, когда мы работали над программой лояльности, у нас возникла проблема с количеством начисляемых клиентам баллов. Проблема была связана с преобразованием типа 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);
100
ответ дан 23 November 2019 в 00:56
поделиться

Они должны были сделать 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");
        }
    }
}
74
ответ дан 23 November 2019 в 00:56
поделиться

Область видимости в C # временами действительно странная. Приведу один пример:

if (true)
{
   OleDbCommand command = SQLServer.CreateCommand();
}

OleDbCommand command = SQLServer.CreateCommand();

Не удалось скомпилировать, потому что команда повторно объявлена? Есть некоторые интересные предположения относительно того, почему это работает таким образом в этом потоке в stackoverflow и в моем блоге .

2
ответ дан 23 November 2019 в 00:56
поделиться

Насколько я знаю, не из коробки. WPF основан на DirectX, но поскольку WPF также поддерживается в Windows XP, он основан на DirectX 9.

Я знаю, что можно использовать DirectX 10 с WPF, но тогда ваше приложение не сможет работать в XP. .

Есть библиотека для WPF под названием Bling, которая поддерживает DirectX 10 (в Vista и Windows 7), которая может вас заинтересовать. Вы можете найти его здесь . Я не знаю, насколько он зрелый.

Кроме того, я наткнулся на этот блог (в основном на французском), в котором говорится об использовании DirectX 10 с WPF.

Наконец, на CodeProject

есть хорошее введение в использование D3DImage с DirectX . Я знаю, что это не совсем ответ на ваш вопрос, но я решил поделиться им с вами в любом случае. Удачи.

затем: Кто сказал, что вы не можете создать экземпляр интерфейса?

65
ответ дан 23 November 2019 в 00:56
поделиться

Это один из самых необычных файлов, которые я когда-либо видел (не считая те, которые здесь, конечно!):

public class Turtle<T> where T : Turtle<T>
{
}

Он позволяет вам объявить его, но не имеет реального использования, поскольку он всегда будет просить вас обернуть любой класс, который вы поместите в центр, с другой черепахой.

[шутка] Полагаю, это черепахи ... [/ joke]

67
ответ дан 23 November 2019 в 00:56
поделиться

Я нашел второй действительно странный угловой вариант, который намного превосходит мой первый.

Метод String.Equals (String, String, StringComparison) на самом деле не свободен от побочных эффектов.

Я работал над блоком кода, в котором это было в отдельной строке в верхней части некоторой функции:

stringvariable1.Equals(stringvariable2, StringComparison.InvariantCultureIgnoreCase);

Удаление этой строки привело к переполнению стека где-то еще в программе.

Код оказался неверным. установить обработчик того, что по сути было событием BeforeAssemblyLoad, и попытаться выполнить

if (assemblyfilename.EndsWith("someparticular.dll", StringComparison.InvariantCultureIgnoreCase))
{
    assemblyfilename = "someparticular_modified.dll";
}

К настоящему времени мне не нужно было вам рассказывать. Использование языка и региональных параметров, который ранее не использовался при сравнении строк, вызывает сборку нагрузки. InvariantCulture не является исключением.

28
ответ дан 23 November 2019 в 00:56
поделиться

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 .

33
ответ дан 23 November 2019 в 00:56
поделиться

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 !!!

Полное описание здесь

10
ответ дан 23 November 2019 в 00:56
поделиться

Назначьте это!


Это тот, который я люблю спрашивать на вечеринках (вероятно, поэтому меня больше не приглашают):

Можете ли вы скомпилировать следующий фрагмент кода?

    public void Foo()
    {
        this = new Teaser();
    }

Простым читом может быть:

string cheat = @"
    public void Foo()
    {
        this = new Teaser();
    }
";

Но настоящее решение таково:

public struct Teaser
{
    public void Foo()
    {
        this = new Teaser();
    }
}

Итак, малоизвестный факт, что типы значений (структуры) могут переназначать свои эта переменная.

111
ответ дан 23 November 2019 в 00:56
поделиться

Следующее может быть общим знанием, которого мне просто не хватало, но эх. Некоторое время назад у нас был случай с ошибкой, который касался виртуальных свойств. Немного абстрагируясь от контекста, рассмотрите следующий код и примените точку останова к указанной области:

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 похожа, .. делает что-то забавное»

7
ответ дан 23 November 2019 в 00:56
поделиться

Я не уверен, что это 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

6
ответ дан 23 November 2019 в 00:56
поделиться

Это самое странное, с которым я столкнулся случайно:

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 , подставляется пустая строка.

15
ответ дан 23 November 2019 в 00:56
поделиться

Есть кое-что действительно интересное в C# - то, как он работает с закрытиями.

Вместо того, чтобы копировать значения стековой переменной в свободную от замыкания переменную, он делает эту магию препроцессора, оборачивая все появления переменной в объект, и таким образом перемещает ее из стека - прямо в кучу! :)

Я думаю, это делает C# даже более функционально полным (или лямбда-полным, а)) языком, чем сам ML (который использует копирование значений стека AFAIK). F# тоже имеет эту возможность, как и C#.

Это действительно приносит мне много радости, спасибо вам, ребята из MS!

Это не странность или угловой случай... но что-то действительно неожиданное для VM-языка, основанного на стеке :)

3
ответ дан 23 November 2019 в 00:56
поделиться

Из вопроса, который я задал не так давно:

Условный оператор не может неявно приводить?

Дано:

Bool aBoolValue;

Где aBoolValue присваивается True или False;

Следующее будет не компилировать:

Byte aByteValue = aBoolValue ? 1 : 0;

Но это будет:

Int anIntValue = aBoolValue ? 1 : 0;

Полученный ответ тоже довольно хорош.

3
ответ дан 23 November 2019 в 00:56
поделиться

Вы когда-нибудь думали, что компилятор 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]
6
ответ дан 23 November 2019 в 00:56
поделиться

Что если у вас есть общий класс, у которого есть методы, которые могут быть неоднозначными в зависимости от аргументов типа? Недавно я столкнулся с этой ситуацией при написании двустороннего словаря. Я хотел написать симметричные методы 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..."

Интересно, что все остальные методы во втором случае остаются пригодными для использования; только вызов теперь уже однозначного метода вызывает ошибку компилятора. Интересный случай, хотя немного маловероятный и неясный.

10
ответ дан 23 November 2019 в 00:56
поделиться

В используемом нами 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 () .

8
ответ дан 23 November 2019 в 00:56
поделиться

C # Accessibility Puzzler


Следующий производный класс обращается к частному полю из своего базового класса, и компилятор молча смотрит на другую сторону:

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;
        }
    }
}

Внутренним классам предоставляется полный доступ к внешним членам класса. В этом случае внутренний класс также является производным от внешнего класса. Это позволяет нам «нарушить» инкапсуляцию закрытых членов.

10
ответ дан 23 November 2019 в 00:56
поделиться

Следующая Ложь печати вместо того, чтобы выдать исключение переполнения:

Console.WriteLine("{0}", yep(int.MaxValue ));


private bool yep( int val )
{
    return ( 0 < val * 2);
}
-4
ответ дан Craig Eddy 23 November 2019 в 00:56
поделиться

У этого был я действительно озадаченный (я приношу извинения за длину, но это - 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());
        }
    }
}
-4
ответ дан Quibblesome 23 November 2019 в 00:56
поделиться

Я думаю, что ответ на вопрос - то, потому что .net использует строку, интернирующую что-то, что могло бы заставить равные строки указывать на тот же объект (так как строки изменяемы, это не проблема)

(я не говорю о переопределенном операторе равенства на строковом классе)

-18
ответ дан James Z 23 November 2019 в 00:56
поделиться