如何从父类中的名称动态设置属性?

Posted

技术标签:

【中文标题】如何从父类中的名称动态设置属性?【英文标题】:How do I Dynamically set properties from the name in a parent class? 【发布时间】:2021-12-30 03:41:31 【问题描述】:

如何将每个 AlarmModel 的“名称”属性动态设置为父类中的模型名称(即 HardwareFault)?

public class NotificationModel

    public string UnrelatedProperty  get; set;   // any solution should ignore other properties.

    public AlarmModel HardwareFault get; set; 

    public AlarmModel TimeoutFault  get; set; 

    public AlarmModel GenericFault  get; set; 


public class AlarmModel

    public string Name  get; set; 

    public bool isActive  get; set; 

    public bool isEnabled  get; set; 

    public bool isSilenced  get; set; 

【问题讨论】:

【参考方案1】:

您应该将属性“名称”移动到父类。并尝试将其扩展/继承到子类。

【讨论】:

您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案2】:

如果您已经初始化 NotificationModel 并且已经初始化了HardwareFaultTimeoutFaultGenericFault 属性,则可以使用此示例:

var notificationModel = new NotificationModel()

    HardwareFault = new AlarmModel(),
    GenericFault = new AlarmModel(),
    TimeoutFault = new AlarmModel()
;

notificationModel?.GetType().GetProperties().Where(p => p.PropertyType.Name == "AlarmModel") // Or p.PropertyType == typeof(AlarmModel)
                                            .ToList().ForEach(alarmModelProperty =>

    // Get AlarmModel property instance
    var alarmModelInstance = alarmModelProperty.GetValue(notificationModel);
    // Get Name property
    var nameProperty = alarmModelIntance?.GetType().GetProperty("Name");
    // Set Name property value with name of AlarmModel property
    nameProperty?.SetValue(alarmModelInstance, alarmModelProperty.Name);
);

如果你有已经初始化NotificationModel,但没有初始化HardwareFaultTimeoutFaultGenericFault属性,你可以使用这个例子:

var notificationModel = new NotificationModel();

notificationModel?.GetType().GetProperties().Where(p => p.PropertyType.Name == "AlarmModel") // Or p.PropertyType == typeof(AlarmModel)
                                            .ToList().ForEach(alarmModelProperty =>

    // Initialize new AlarmModel 
    var alarmModelInstance = Activator.CreateInstance(alarmModelProperty.PropertyType);
    // Get Name property of AlarmModel
    var nameProperty = alarmModelInstance.GetType().GetProperty("Name");
    // Set Name property of AlarmModel
    nameProperty?.SetValue(alarmModelInstance, alarmModelProperty.Name);
    // Set AlarmModel property of NotificationModel
    alarmModelProperty.SetValue(notificationModel, alarmModelInstance);
);

如果您需要使用反射进行完全初始化,可以使用以下示例:

var notificationModelType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(type => type.Name == "NotificationModel"); // Or type == typeof(NotificationModel)
if (notificationModelType is null) // No NotificationModel found in current assembly
    return;

// Initializing NotificationModel
var notificationModel = Activator.CreateInstance(notificationModelType);

notificationModel?.GetType().GetProperties().Where(p => p.PropertyType.Name == "AlarmModel") // Or p.PropertyType == typeof(AlarmModel)
                                            .ToList().ForEach(alarmModelProperty =>

    // Initialize new AlarmModel 
    var alarmModelInstance = Activator.CreateInstance(alarmModelProperty.PropertyType);
    // Get Name property of AlarmModel
    var nameProperty = alarmModelInstance.GetType().GetProperty("Name");
    // Set Name property of AlarmModel
    nameProperty?.SetValue(alarmModelInstance, alarmModelProperty.Name);
    // Set AlarmModel property of NotificationModel
    alarmModelProperty.SetValue(notificationModel, alarmModelInstance);
);

如果NotificationModel 声明不在当前程序集中(所以它不会在Assembly.GetExecutingAssembly().GetTypes() 中) - 您可以在AppDomain.CurrentDomain 中搜索所有已加载的程序集:

var notificationModelType = AppDomain.CurrentDomain.GetAssemblies()
                                                   .SelectMany(assembly => assembly.GetTypes())
                                                   .FirstOrDefault(type => type.Name == "NotificationModel");

【讨论】:

【参考方案3】:

如果我理解正确,您想将每个AlarmModelName 属性设置为父NotificationModel 中的属性名称?

如果是这样,你可以这样做:

public class NotificationModel

    private AlarmModel _hardwareFault;

    private AlarmModel _timeoutFault;

    private AlarmModel _genericFault;

    public string UnrelatedProperty  get; set;   // any solution should ignore other properties.

    public AlarmModel HardwareFault
     
        get => _hardwareFault; 
        set
        
            _hardwareFault = value;
            SetName(value);
        
    

    public AlarmModel TimeoutFault 
    
        get => _timeoutFault; 
        set
        
            _timeoutFault= value;
            SetName(value);
        
    

    public AlarmModel GenericFault 
    
        get => _genericFault; 
        set
        
            _genericFault= value;
            SetName(value);
        
    

    private void SetName(AlarmModel model, [CallerMemberName] string propertyName = null)
    
        model.Name = propertyName;
    

【讨论】:

private SetName 缺少 void 的返回类型。另外我建议为model.Name(例如if (model is not null) model.Name = propertyName;)添加一个空检查以避免NullReferenceException

以上是关于如何从父类中的名称动态设置属性?的主要内容,如果未能解决你的问题,请参考以下文章

java 中 super和this的异同

Python类 - 从父类继承属性到顶层

是否可以从父类指针向下转换为第二个子类中的子类指针?

尽管子类中也有相同的方法,但如何从父类停止子类对象的调用方法

C#在父类中获取子类的类名

爪哇 |父类和子类中的静态变量|从父类访问子 var 值