Базовый общий абонент для событий [дубликат]

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

Пример:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

Вы можно просто избежать этого, проверив, является ли переменная не нулевой:

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

Чтобы полностью понять, почему выбрано исключение NullReferenceException, важно знать разницу между типами значений и ссылочные типы .

Итак, если вы имеете дело со типами значений, NullReferenceExceptions не может произойти. Хотя вам нужно поддерживать оповещение при работе со ссылочными типами!

Только ссылочные типы, как следует из названия, могут содержать ссылки или буквально буквально ничто (или «нуль»). Если типы значений всегда содержат значение.

Типы ссылок (эти должны быть проверены):

  • динамический
  • объект
  • string

Типы значений (вы можете просто игнорировать эти):

  • Числовые типы
  • Интегральные типы
  • Типы с плавающей запятой
  • decimal
  • bool
  • Пользовательские структуры

3
задан Richard Fawcett 4 February 2011 в 16:12
поделиться

6 ответов

Может быть, что-то подобное сделало бы работу тоже?

class Test<T> {
    public Test(Proxy<T> proxy) { this.MyProxy = proxy; }
    public Proxy<T> MyProxy { get; private set; }
}
2
ответ дан Botz3000 27 August 2018 в 08:56
поделиться

Как я могу это сделать без необходимости иметь два родовых типа в MyClass. В конце концов, если мы знаем, что первым является SomeProxy, ему следует следовать, что вторым является SomeClass.

Хотя вы, кажется, нашли ответ на основную часть вопроса, я решил, что я Я предлагаю свое понимание этой части. Похоже, вы хотите, чтобы вы могли сделать что-то вроде этого:

class Proxy<T> 
{ 
    T Value { get; set; }
}
class MyClass<U> where U : Proxy<> { }

и чтобы компилятор заполнил параметр типа Proxy, когда вы предоставляете U. Поскольку вы объявили U как наследуемый от Proxy, вы должны использовать один из методов в Proxy, который, вероятно, использует параметр T, например:

class MyClass<U> where U : Proxy<>
{
    void SomeMethod(U parameter)
    {
        var local = parameter.Value;
        //more code here...
    }
}

Теперь, что такое компилятор, который должен вывести здесь local? Это основная проблема, которую я вижу, что делает такую ​​функцию, если возможно, трудно реализовать. Если вы не хотите использовать какие-либо методы, использующие общий тип прокси-сервера, вместо этого вы можете сделать не общий базовый класс и использовать его для U и обойти всю проблему.

Я а не писатель-компилятор, но на ум приходит пара возможностей того, как это можно решить. Он мог бы просто сказать объект (или любое другое ограничение, которое вы указали в параметре type в Proxy), но это не кажется совершенно правильным или совершенно нормальным дженериком. Это также потребовало бы, чтобы CLR разрешала открывать общие типы как ограничение на общий параметр, что я сомневаюсь в этом. Другой вариант, который я мог видеть, - это тип, который фактически имеет параметр второго типа, и компилятор, чтобы дать вам синтаксический сахар, чтобы облегчить его.

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

0
ответ дан Gideon Engelberth 27 August 2018 в 08:56
поделиться

Если вы хотите, чтобы T оставался общим в Myclass, то экземпляр MyClass все еще должен разрешать все внутренние используемые общие типы, и вы должны его где-то объявить. Путь к вам - это многословный способ:

public class MyClass<U, T> where U : Proxy<T>

Если вам не нужен общий тип T в MyClass, тогда создайте интерфейс и используйте его вместо:

public interface IProxy { ... }
public class SomeClass { ... }
public class SomeProxy : Proxy<SomeClass>, IProxy { ... }
public class MyClass<U> where U : IProxy

, а затем в клиенте где-то:

var proxyWrapper = new MyClass<SomeProxy>();

Но обратите внимание, что вы не можете использовать тип T в объявлении интерфейса, а тип U теперь более общий, чем раньше.

0
ответ дан Imre Pühvel 27 August 2018 в 08:56
поделиться

Извините, вы просто не можете сделать это на C #, не имея MyClass generic для обоих типов (если вы не хотите использовать отражение для создания экземпляров его.)

1
ответ дан mquander 27 August 2018 в 08:56
поделиться

Оказывается, что все классы SomeProxy, с которыми я хочу иметь дело, на самом деле просто переопределяют один метод из Proxy<T>, который имеет подпись:

 T LoadInternal(Identifier id)

Итак, что я сделал создается внутренний класс внутри MyClass, который принимает Func<Identifier, T> в своем конструкторе. Затем я могу передать Func<Identifier, T> в качестве параметра конструктору MyClass и использовать свой подкласс вместо SomeProxy.

Кажется немного запутанным, но он работает для меня. Подводя итог, теперь у меня есть:

public class MyClass<T>{
    private SomeProxy theProxy;

    public MyClass(Func<Identifier, T> loadDelegate){
        theProxy = new SomeProxy(loadDelegate);
    }

    /* Other methods here */

    class SomeProxy : Proxy<T>{
        private Func<Identifier, T> m_loadInternal;

        public SomeProxy(Func<Identifier, T> loadInternal){
            m_loadInternal = loadInternal;
        }

        protected override T LoadInternal(Identifier id){
            return m_loadInternal(id);
        }
    }
}

Итак, из клиентского кода вместо написания класса, который расширяет прокси и затем переопределяет LoadInternal в этом классе, я просто создаю MyClass, используя:

var myClass = new MyClass<T>(x => CodeWhichReturnsT());
0
ответ дан Richard Fawcett 27 August 2018 в 08:56
поделиться

У вас может быть интерфейс IMyClass<SomeProxy> и фабричный метод, который создает и возвращает экземпляр MyClass<SomeProxy, SomeClass>. Возможно, вам понадобится создать экземпляр с помощью Reflection.

У меня есть пример кода здесь аналогичной ситуации: конечный пользователь только заботится о одном типе параметра, но потребности реализации иметь два. В моем примере мне не нужно использовать Reflection для создания экземпляра, но это похоже на то, что вам может понадобиться.

То, что вы пытаетесь сделать, возможно с использованием конструкций времени компиляции, таких как C ++ шаблонов, но не конструкций времени выполнения, таких как генераторы C #.

1
ответ дан Stephen Cleary 27 August 2018 в 08:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: