Найдите все классы, производные от определенного базового класса, и добавьте их в реестр.

У меня есть базовый класс BaseStatus, который выглядит так:

 public class BaseStatus
    {       
        public int UnitId { get; protected set; }
        public UInt16 StatusValue { get; protected set; }
        public string StatusCode { get; protected set; }
        public string StatusDescription { get; protected set; }

        public BaseStatus()
        {
            this.UnitId = -1;
            this.StatusValue = 0;
            this.StatusCode = null;
            this.StatusDescription = null;
        }
}

Кроме того, у меня есть два или более других базовых класса, которые происходят от BaseStatus и определяют другой идентификатор устройства. Например, два класса

public class BaseGlobalStatus : BaseStatus
    {  
        public BaseGlobalStatus()
        {
            base.UnitId = -1;
        }
    }

    public class BaseGcmGdmStatus : BaseStatus
    {
        public BaseGcmGdmStatus()
        {
            base.UnitId = 2;
        }
    }

    public class BaseCcuStatus : BaseStatus
    {
        public BaseCcuStatus()
        {
            base.UnitId = 1;
        }
    }

Фон в том, что я хочу получить, например, BaseCcuStatus и иметь правильный UnitId в производном классе.

Теперь я определяю свои правильные классы статуса, например:

public class StatStErrDefinition : BaseGlobalStatus
    {
        public StatStErrDefinition()
            : base()
        {
            base.StatusDescription = "Kommando nicht zulässig, unit im state ERROR";
            base.StatusCode = "STAT_ST_ERR";
            base.StatusValue = 3;
        }
    }

    public class GcmStErrDefinition : BaseGcmGdmStatus
    {
        public GcmStErrDefinition()
            : base()
        {
            base.StatusDescription = "Kommando nicht zulässig, unit im state ERROR";
            base.StatusCode = "STAT_ST_ERR";
            base.StatusValue = 3;
        }
    }

    public class CcuStErrDefinition : BaseCcuStatus
    {
        public CcuStErrDefinition()
            : base()
        {
            base.StatusDescription = "Kommando nicht zulässig, unit im state ERROR";
            base.StatusCode = "STAT_ST_ERR";
            base.StatusValue = 3;
        }
    }

Насколько я понимаю, три класса StatStErrDefinition, GcmStErrDefinition и CcuStErrDefinition должны иметь UnitId, установленный в производном BaseClass?

Теперь, когда я определил свои три класса состояния, я хочу поместить их в реестр. В настоящее время я использую этот фрагмент кода, чтобы попытаться их получить. Проблема в том, что в результате нет элементов.

  registry = new StatusDictionary<UInt16, BaseStatus>();
                    var unitStatus = typeof(BaseStatus)
                                    .Assembly.GetTypes()
                                    .Where(x => x.BaseType == typeof(BaseStatus))
                                    .Select(x => new 
                                                { 
                                                    StatusType = x, 
                                                    UnitId = x.GetProperty("UnitId", BindingFlags.Public) 
                                                    StatVal = x.GetProperty("StatusValue", BindingFlags.Public) 
                                                }
                                            )
                                    .Where(x => x.StatVal != null && x.UnitId != null)
                                    .Select(x => new
                                    {
                                        UnitId = (int)x.UnitId.GetValue(null, null),
                                        StatusValue = (UInt16)x.StatVal.GetValue(null, null),
                                        Factory = (Func<BaseStatus>)(() => ((BaseStatus)Activator.CreateInstance(x.StatusType)))
                                    });


                    try
                    {
                        foreach (var status in unitStatus)
                        {
                            if (status.UnitId == unitId 
                                || status.UnitId < 0)
                                registry.Register(status.StatusValue, status.Factory);
                        }
                    }
                    catch (Exception ex)
                    {
                        string temp = ex.Message;
                    }

После выражения LINQ переменная unitStatus пуста...

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

  stat = StatusContainer.GetRegistry(this.unitTypeId).GetInstance(this.StatusValue);

Для информации: я хочу получить класс статуса, который должен быть в реестре по unittypeid и конкретному значению статуса. В настоящее время мой метод реестра не работает, потому что он не может найти ни одного класса. Значит, где-то должна быть ошибка. заранее спасибо

#Обновление 1

Я немного изменил свой функционал:

 registry = new StatusDictionary<UInt16, BaseStatus>();


                        //get all types of cucrent assembly
                        var allAssemblyTypes = Assembly.GetCallingAssembly().GetTypes();
                        //get all types from base status
                        var baseStatusTypes = allAssemblyTypes.Where(x => x.BaseType == typeof(BaseStatus));

                        //Place all concrete types in the foundtypes
                        List<Type> foundTypes = new List<Type>();
                        foreach (Type item in baseStatusTypes)
                        {
                            var temp = allAssemblyTypes.Where(x => x.BaseType == item)
                                         .Select(x => new
                                                {
                                                    StatusType = x,
                                                    UnitId = x.GetProperty("UnitId", BindingFlags.Public),
                                                    StatVal = x.GetProperty("StatusValue", BindingFlags.Public),
                                                }
                                            );
                        }

Temp теперь содержит правильный тип. Проблема в том, что если temp является типом StatStErrDefinition, свойство StatusValue и UnitId имеет значение null. Дело в том, что эти члены являются членами экземпляра. Есть ли способ получить значения из них?


person Daniel W.    schedule 07.08.2013    source источник
comment
x.BaseType даст вам немедленное наследование, а не родителя родителя, как вы можете прочитать здесь - msdn.microsoft.com/en-us/library/system.type.basetype.aspx   -  person No Idea For Name    schedule 07.08.2013


Ответы (1)


Прежде всего: ваш запрос linq довольно длинный. разделите его на другой шаг и сохраните их в разных переменных (или сделайте из них свойства, как вам больше нравится)

Это

  1. легко читать / поддерживать
  2. легко отлаживать

С этим гивином, я думаю, вы сможете решить свою проблему :)

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

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

 public static object GetPropValue(Type src, string propName)
 {
     var prop = src.GetProperty(propName);
     var instance = Activator.CreateInstance(src);
     var value = prop.GetValue(instance);
     return value;
 }

Вместо

UnitId = x.GetProperty("UnitId", BindingFlags.Public),

использовать

UnitId = GetPropValue(x,"UnitId"),
person lordkain    schedule 07.08.2013
comment
Извините, был занят! Да, это мне очень помогло, и это работает так, как должно! Благодарю вас! - person Daniel W.; 07.08.2013