简体   繁体   English

使用整数设置枚举属性并验证参数

[英]Set an enum property using an integer & validate the argument

EDIT: I have changed the title of the question to include the validation of the argument, to be clearer what I am asking. 编辑:我已经改变了问题的标题,包括对论证的验证,更清楚我要问的是什么。

I am attempting to create a class in C# which has a property that is set with an int and returns an enum, this may be really basic but I am a C# noob. 我试图在C#中创建一个类,它有一个用int设置的属性并返回一个枚举,这可能是基本的,但我是一个C#noob。

The setting by use of an int argument is a particular limitation that I won't go into and is something that is getting set over COM in Vbscript. 使用int参数的设置是一个特殊的限制,我不会进入,并且是在Vbscript中设置COM的东西。

I am looking to create these RSSCalendarDay objects so they can be put in a list and each have a unique RSSCalendarRuleDay from Sunday to Saturday (1 to 7). 我正在寻找创建这些RSSCalendarDay对象,以便它们可以放在一个列表中,每个对象从周日到周六(1到7)都有一个唯一的RSSCalendarRuleDay。

Its for part of a really basic approach to using xCal with local data to make recurring events. 它是使用xCal和本地数据来制作重复事件的真正基本方法的一部分。

My code so far is below and you can see the get & set are incomplete, I am stuck on the validation of the argument (check its an int first, etc), thats what I was previously trying to use dayOrderValue for, and all I could find online in relation was the use of int.Parse and int.TryParse but they were for parsing a string, not for what I want to do. 到目前为止,我的代码在下面,你可以看到get&set是不完整的,我坚持参数的验证(首先检查它是一个int,等等),这就是我之前尝试使用dayOrderValue的东西,以及我所有的可以在线找到的是使用int.Parse和int.TryParse,但是它们用于解析字符串,而不是我想做的事情。

public class RSSCalendarDay {

    private RSSCalendarRuleDay? _dayOrder;
    /// <summary>
    /// Passed an Integer from 1 to 7 to represent the particular day of the week as an enum
    /// </summary>
    public RSSCalendarRuleDay? DayOrder {
        get {
                       // TODO
        } 
        set {
            if (value != null) {
                int dayOrderValue;
                if () {
                    throw new ArgumentException("Invalid day order specified");
                }
                if(dayOrderValue < 1 || dayOrderValue > 7) {
                    throw new ArgumentException("Invalid day type specified (out of day range of 1 to 7)");
                }
                _dayOrder = (RSSCalendarRuleDay) dayOrderValue;
            }
            else {
                _dayOrder = null;
            }
        } 
    }
    public DateTime? TimeOpens { get; set; }
    public DateTime? TimeCloses { get; set; }

    /// <summary>
    /// These are the relevant BYDAY abbreviations used in the xCal recurring rule specification
    /// to represent what days a recurring event is open in a comma separated list
    /// </summary>
    public enum RSSCalendarRuleDay {
        SU=1,MO=2,TU=3,WE=4,TH=5,FR=6,SA=7
    }
}

You can convert an int to an Enum like so 你可以像这样将int转换为Enum

RSSCalendarRuleDay foo = Enum.ToObject(typeof(RSSCalendarRuleDay) , intValue);

Or by simply casting it 或者简单地投下它

RSSCalendarRuleDay foo = (RSSCalendarRuleDay) intValue;

Do note that since you're using a setter, the setter will expect an Enum value, not an integer, so you will need to cast it before using the setter. 请注意,由于您使用的是setter,因此setter会期望Enum值,而不是整数,因此您需要使用setter 之前将其强制转换。

Do note that ToObject will always succeed, even if the value is not defined for the Enum. 请注意,即使未为Enum定义值,ToObject也将始终成功。 if you want to do a bounds check, you can use the Enum.IsDefined method 如果要进行边界检查,可以使用Enum.IsDefined方法

var exists = Enum.IsDefined(typeof(RSSCalendarRuleDay) , intValue);

You cannot define a property that is “set with an int and returns an enum”. 您无法定义“使用int设置并返回枚举”的属性。 By design, the getter and the setter of a property be declared of the same type. 根据设计,属性的getter和setter声明为相同类型。

However, what you can do is define two properties which both access the same backing field, one as your enum, and the other cast to an int: 但是,您可以做的是定义两个属性,它们都访问相同的支持字段,一个作为枚举,另一个转换为int:

public class RSSCalendarDay
{
    private RSSCalendarRuleDay? dayOrder;

    public RSSCalendarRuleDay? DayOrder
    {
        get { return this.dayOrder; }
        set { this.dayOrder = value; }
    }

    public int DayOrderInt
    {
        get { return this.dayOrder.HasValue ? (int)this.dayOrder: 0; }
        set { this.dayOrder = value != 0 ? (RSSCalendarRuleDay?)value : null; }
    }
}

In the above code, I have simplified your logic to set the backing field to null if you specify an int value of 0 (and vice versa); 在上面的代码中,如果指定int值为0(反之亦然),我已经简化了逻辑以将后备字段设置为null; this may not be what you want. 这可能不是你想要的。

Consequently, the two following assignments will have identically the same effect: 因此,以下两个分配将具有相同的效果:

RSSCalendarDay cd1 = new RSSCalendarDay();
cd1.DayOrder = RSSCalendarRuleDay.TH;

RSSCalendarDay cd2 = new RSSCalendarDay();
cd2.DayOrderInt = 5;

Edit : If you want to perform validation of the argument, you can use a similar approach: 编辑 :如果要执行参数验证,可以使用类似的方法:

public class RSSCalendarDay
{
    private RSSCalendarRuleDay dayOrder;

    public RSSCalendarRuleDay DayOrder
    {
        get { return this.dayOrder; }
        set { this.dayOrder = value; }
    }

    public int DayOrderInt
    {
        get 
        { 
            return (int)this.dayOrder;
        }
        set
        {
            if (!Enum.IsDefined(typeof(RSSCalendarRuleDay), value))
                throw new ArgumentException("Invalid day value specified (out of day range of 1 to 7).");
            this.dayOrder = (RSSCalendarRuleDay)value; 
        }
    }
}

Enum.IsDefined checks whether the enumeration contains the specified value. Enum.IsDefined检查枚举是否包含指定的值。 In your case, the condition is equivalent to value < 1 || value > 7 在您的情况下,条件等于value < 1 || value > 7 value < 1 || value > 7 . value < 1 || value > 7

Note that in the above code, DayOrder is not nullable, and 0 is considered an invalid day value. 请注意,在上面的代码中, DayOrder不可为空, 0被视为无效的日期值。

Edit 2 : Re the default value issue: My personal preference is to define the 0 th member of the enumeration to be unknown; 编辑2 :重新设置默认值:我个人的偏好是将枚举的 0 成员定义为未知; to continue with your two-letter convention, I'm naming it NA (for “not available”). 继续你的双字母约定,我将其命名为NA (“不可用”)。

public enum RSSCalendarRuleDay {
    NA=0,SU=1,MO=2,TU=3,WE=4,TH=5,FR=6,SA=7
}

This is convenient because, when you initialize an RSSCalendarDay instance without explicitly setting its dayOrder field, it would automatically default to RSSCalendarRuleDay.NA . 这很方便,因为在初始化RSSCalendarDay实例而没有显式设置其dayOrder字段时,它会自动默认为RSSCalendarRuleDay.NA The second snippet I gave above would also work unchanged with this alteration, since Enum.IsDefined would now accept a range of 0–7 (rather than 1–7). 我上面给出的第二个片段也会随着这种改变而改变,因为Enum.IsDefined现在会接受0-7(而不是1-7)的范围。

Don't over-complicate your code: enums are represented internally by numbers ( int per default), so it is possible to cast from an int to an enum value (and vice-versa). 不要使代码过于复杂:枚举在内部由数字表示(默认为int ),因此可以从int转换为enum值(反之亦然)。

So here's how you could simply do: 所以这就是你如何做到的:

public RSSCalendarRuleDay DayOrder { get; set; }

...

RSSCalendarDay xx = new RSSCalendarDay(...)
xx.DayOrder = (DayOrder)4;  // Will set WE for the DayOrder property

...

// If you need to get the value as an int
int dayOrderAsInt = (int)xx.DayOrder;

// Still possible to affect invalid values however
RSSCalendarRuleDay z = (RSSCalendarRuleDay)8;

// So if you want to check for int validity:
if (Enum.IsDefined(typeof(RSSCalendarRuleDay), dayOrderAsInt))
{
    // If we're here, the value is valid !
}

Also, make sure you really need DayOrder to be nullable (if it's not the case, remove the ?). 另外,确保你真的需要DayOrder可以为空(如果不是这样,请删除?)。

The issue is that you can't receive anything different than an Enum in the setter for your property since you declared it as Enum . 问题是,由于您将其声明为Enum ,因此您无法在属性的setter中收到与Enum不同的任何内容。 One alternative could be something like this: 一种替代方案可能是这样的:

private int? dayOrderInt;

public int? DayOrderInt
{
     get { return dayOrderInt; }
     set { if (value < 1 || value > 7) throw new ArgumentException(string.Format("{0} is an invalid day of the week", value)); dayOrderInt = value; }
}

public RSSCalendarRuleDay? DayOrder
{
    get { if (DayOrderInt.HasValue) return (RSSCalendarRuleDay)DayOrderInt; return null; }
}

以下对我有用:

RSSCalendarRuleDay Example = (RSSCalendarRuleDay)1; 

I don't think that is achievable. 我不认为这是可以实现的。 You are setting your property type to RSSCalendarRuleDay? 您将属性类型设置为RSSCalendarRuleDay? and when you want to pass az integer to it the compiler will throw an error. 当你想将az整数传递给它时,编译器将抛出一个错误。 And by the way this approach is very confusing (like when you intended to return an IEnumerable but sometimes you do return null). 顺便说一句,这种方法非常混乱(比如当你打算返回一个IEnumerable但有时你会返回null)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM