2016-01-18 3 views
1

Пожалуйста, помогите мне понять это. У меня есть вид завода, который выглядит как этотДоступ к свойствам объекта, присвоенного var

public static class FactoryForAnything 
{ 
    public static object GetInstanceOf<T>() where T : class 
    { 
     return Activator.CreateInstance(IsType<T>(), true); 
    } 
    private static Type IsType<T>() 
    { 
     if (typeof(T).IsSubclassOf(typeof(EntityBaseSupertype)) == true) 
     { 
      return typeof(T); 
     } 
     else if (typeof(T).IsSubclassOf(typeof(ValueObject<>)) == true) 
     { 
      return typeof(T); 
     } 
     else 
      return null; 
    } 

Намерение принимает класс в качестве параметра и возвращает объект этого класса

EntityBaseSupertype hon =(EntityBaseSupertype) FactoryForAnything.GetInstanceOf<User>(); 
var hon = FactoryForAnything.GetInstanceOf<User>(); 

Calling завод с EntityBaseSupertype получает меня объект и на него ссылается абстрактный базовый класс всех объектов, поэтому я могу получить доступ к файлам/свойствам/членам объекта. Вызов фабрики с var получает меня объект, но он не дает мне доступ к полям/свойствам и так далее. Я понимаю, что это уродливый дизайн, и он не будет использоваться, но мой вопрос заключается в том, почему я не могу обращаться к объекту с помощью var? Почему?

+0

Потому что ... ваш метод возвращает 'object'? Попросите его вернуть 'T' (вам, конечно, нужно сделать явное приведение). – Luaan

+0

Я не уверен, но вы можете заставить ограничение иметь пустой конструктор с 'new()', а затем использовать его для экземпляра вашего типа T. –

ответ

0

Компилятор пытается определить реальный тип var из кода, но для

var hon = FactoryForAnything.GetInstanceOf<User>(); 

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

Вы можете получить проверки метаданных с

EntityBaseSupertype hon = FactoryForAnything.GetInstanceOf<User>() as EntityBaseSupertype; 

Но это проверка во время выполнения. Компилятор будет интерпретировать hon как EntityBaseSupertype и позволит вам получить доступ к публичным объектам и членам. CLR будет искать метаданные объекта во время выполнения и возвращать значение null, если объект не может быть назначен EntityBaseSupertype, тогда как приведение будет вызывать InvalidCastException, если это невозможно назначить.

1

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

var hon = FactoryForAnything.GetInstanceOf<User>(); 

эквивалентно:

object hon = FactoryForAnything.GetInstanceOf<User>(); 

с компилятором (а также IntelliSense) основывает поиск члена на Type переменной доступ, который в этом случае равен object (или один из его базовых классов. Которые не существуют, потому что ... это object, и он не имеет базового класса).

При компиляции следующего кода:

EntityBaseSupertype hon = (EntityBaseSupertype) FactoryForAnything.GetInstanceOf<User>(); 

Вы делаете две вещи:

  • Explicitly castingobject вернулся из GetInstanceOf в EntityBaseSupertype, который сгенерирует InvalidCastException если возвращаемый Type недопустим для это литье.
  • Присвоение литой ценности переменной TypeEntityBaseSupertype.

Затем поиск членов может найти членов EntityBaseSupertype и это базовые классы.


Некоторые побочные ноты:

  • GetInstanceOf<T> будет всегда возвращать object из TypeT, поэтому вы должны изменить его подпись:

    public static T GetInstanceOf<T>() where T : class 
    

    Если это могло бы вернуть Type, который не является T, тогда этот метод является рискованным, потому что код, который будет его вызывать, может получить неожиданные результаты и не должен делать сами броски.

  • В таких случаях вы должны использовать IsAssignableFrom вместо IsSubclassOf для поддержки Covariance and Contravariance.

  • Преобразование возвращаемого значения с as ключевого слова является более безопасным, так как она возвращает null, когда не удалось, вместо того, чтобы бросать InvalidCastException.

  • Именование не-булево метод IsXXXXX делает следующее å код немного менее читабельным, поэтому, немного меньше ремонтопригодны, а также ваш метод IsType возвращает null, который может вызвать ваш другой способ бросить unindicative Exception когда Type является недействительным.