I have a panel with a dropdown; which I use to set a field in my project.
public class projectclass
{
public enum mainpriority
{
basic,
urgent,
critical
};
public mainpriority _priorityfield { get; set;}
}
The project class use an enum for this field, so to populate the dropdown I do this, to populate it:
mydropdown.options.Clear();
foreach (projectclass._priorityfield priority in projectclass._priorityfield.GetValues(typeof(projectclass._priorityfield)))
{
mydropdown.options.Add( new Dropdown.OptionData() {text = priority.ToString()});
}
This allow me to display the field in the dropbox, for each instance of the projectclass.
All is good in this direction, but if I want to do the opposite (change the value in the dropdown, and change the class field accordingly), I can't make it work.
The main issue is that I try to assign to the class, the value as int (which is what I get back from the dropdown.value() method), but VS tell me that it is not possible to set a _priorityfield type with an int type.
Isn't the enum, equivalent to 0,1,2.....n; so you can either use "basic" or 0 as value?
This is what I do to set the class instance value, from the dropdown, using the onValueChanged delegate
private void UpdatePriority(Dropdown priority)
{
int tempvalue = priority.value;
projectclass_instance1._priorityfield = tempvalue;
}
I assumed that I can pass an int, but VS says that is not possible. I could map each value of the dropdown to an entry in the enum, but I am not sure that it is actually the best solution.
Thanks to Ehsan for the solution.
The error is because I need to cast the int value as enum type, so the value will be correctly recognized.
Related
In prior versions of C#, if you wanted to prevent a null reference exception, you needed to build your setters defensively:
public Guid ItemId { get; set; } //foreign key, required
private Item _item;
public virtual Item Item {
get {
return _item;
}
set {
if(value == null) throw new ArgumentNullException(nameof(value));
_item = value;
ItemId = value.ItemId;
}
}
With more modern implementations, this can be condensed a certain amount using the null-coalescing operator and expression bodies:
private Item _item;
public virtual Item Item {
get => _item;
set => _item = value ?? throw new ArgumentNullException(nameof(value));
}
However, I am curious if this could not be condensed entirely down into a variation of the standard reference:
public virtual Item Item { get; set; }
Such that you do not have to define a private item.
Suggestions? Or is the second code block as efficient/simple as I can get?
I am looking for a solution within the current C# framework, not something I have to spend money on. Right now my use case proposition does not support a paid product
Disclaimer: Those are potential 'alternative' ways of filtering out invalid assignments into properties. This might not provide a straight answer to the question, but rather give ideas how to go on about doing it more generically without defining private properties and defining getters and setters explicitly.
Depending on what Item actually is, you could perhaps create a non-nullable type of Item by creating it as a struct.
Non nullable types are called structs. They are nothing new, they are value types which allow to store properties of type int, string, bool etc.
As on MSDN:
A struct type is a value type that is typically used to encapsulate
small groups of related variables, such as the coordinates of a
rectangle or the characteristics of an item in an inventory.
The following example shows a simple struct declaration:
public struct Book
{
public decimal price{ get; set;}
public string title;
public string author;
}
Reference
Edit (Struct should be sufficient if the object is supposed to be non-nullable type, however if we're talking properties of the class then read below.) :
Another way would be using OnPropertyChanged event which is part of the INotifyPropertyChanged interface.
While the event does not explicitly give you the value that has been changed to, you can grab it as it does provide you the property name. So you could run your validation post assignment and throw then, I suppose however it might not be the best option.
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var propertyValue = sender.GetType().GetProperty(e.PropertyName).GetValue(sender);
}
Another solution would be using DataAnnotations and add Required attributes on your properties. If I'm not mistaken they will not throw straight away, until you call your own validate function to validate the class, I guess, combined with the above method this would work pretty well and would be pretty generic. Once written you wouldn't have to write your getters and setters explicitly but rather attach just one event to your class and validate it once a property changes.
Here's a small example:
Your Item model for example...
public class Item
{
[Required]
public string Name { get; set; }
}
You would then implement a generic function which would validate all properties.
public bool TryValidate(object #object, out ICollection < ValidationResult > results) {
var context = new ValidationContext(#object, serviceProvider: null, items: null);
results = new List <ValidationResult> ();
return Validator.TryValidateObject(
#object, context, results,
validateAllProperties: true
);
}
Inside that function you would of course throw an exception if validation failed, your results array would contain properties that it failed on an default messages if I'm not mistaken. I believe this is a bit complex, but if you're looking for reducing the number of properties and setter implementations, this could be a step forward. I'm not sure on the overhead etc. Personally, I think on a larger scale, this would be super useful to validate models which are created on the fly from db data or any external source.
Validator Reference | Data Annotations Reference | ValidationResults Reference | PropertyChanged MSDN Sample
I have an enum on helper library in my solution.
For example
public enum MyEnum
{
First,
Second
}
I want to use MyEnum in a few another project. I want to decorate this enum in each project with own attribute like this:
public enum MyEnum
{
[MyAttribute(param)]
First,
[MyAttribute(param2)]
Second
}
How to decorate enum from another library with own local attribute?
You can't do what you've described - the best you can do is to create a new Enum that uses the same set of values. You will then need to cast to the "real" enum whenever you use it.
You could use T4 templates or similar to generate the attributed enum for you - it would be much safer that way as it would be very easy to map the wrong values, making for some very subtle bugs!
Linqpad Query
enum PrimaryColor
{
Red,
Blue,
Green
}
enum AttributedPrimaryColor
{
[MyAttribute]
Red = PrimaryColor.Red,
[MyAttribute]
Blue = PrimaryColor.Blue,
[MyAttribute]
Green = PrimaryColor.Green
}
static void PrintColor(PrimaryColor color)
{
Console.WriteLine(color);
}
void Main()
{
// We have to perform a cast to PrimaryColor here.
// As they both have the same base type (int in this case)
// this cast will be fine.
PrintColor((PrimaryColor)AttributedPrimaryColor.Red);
}
Attributes are compile-time additions (metadata) to code. You can not modify them when using the compiled code assembly.
(Or perhaps you could if you are a diehard low-level IL wizard, but I certainly am not...)
If your enum values require modification or parameters at various places, then you should consider other solutions, e.g. a Dictionary or even a Database Table.
E.g. using a Dictionary:
var values = new Dictionary<MyEnum, int>()
{
{ MyEnum.First, 25 },
{ MyEnum.Second, 42 }
};
var valueForSecond = values[MyEnum.Second]; // returns 42
You can do something like this, but it will be tedious.
The idea is to use your project settings to allow the change when you import the enum in a new project.
First, you will need 2 attributes:
// This one is to indicate the format of the keys in your settings
public class EnumAttribute : Attribute
{
public EnumAttribute(string key)
{
Key = key;
}
public string Key { get; }
}
// This one is to give an id to your enum field
[AttributeUsage(AttributeTargets.Field)]
public class EnumValueAttribute : Attribute
{
public EnumValueAttribute(int id)
{
Id = id;
}
public int Id { get; }
}
Then, this method:
// This method will get your attribute value from your enum value
public object GetEnumAttributeValue<TEnum>(TEnum value)
{
var enumAttribute = (EnumAttribute)typeof(TEnum)
.GetCustomAttributes(typeof(EnumAttribute), false)
.First();
var valueAttribute = (EnumValueAttribute)typeof(TEnum).GetMember(value.ToString())
.First()
.GetCustomAttributes(typeof(EnumValueAttribute), false)
.First();
return Settings.Default[String.Format(enumAttribute.Key, valueAttribute.Id)];
}
I did not check if the type is correct, not even if it finds any attributes. You will have to do it, otherwise you will get an exception if you don't provide the right type.
Now, your enum will look like that:
[Enum("Key{0}")]
public enum MyEnum
{
[EnumValue(0)] First,
[EnumValue(1)] Second
}
Finally, in your project settings, you will have to add as many lines as the number of members in your enum.
You will have to name each line with the same pattern as the parameter given to EnumAttribute. Here, it's "Key{0}", so:
Key0: Your first value
Key1: Your second value
etc...
Like this, you only have to change your settings values (NOT THE KEY) to import your enum and change your attributes to a project to another.
Usage:
/*Wherever you put your method*/.GetEnumAttributeValue(MyEnum.First);
It will return you "Your first value".
See below enum contains two members: Test and Production
public enum OTA_HotelInvCountNotifRQTarget
{
Test,
Production,
}
I'm looking for the way to add and use Null value in above enum from code like :
inv.Target = OTA_HotelInvCountNotifRQTarget.Null; // Not allowed
Update:
I do not want to add extra NULL in above enum, I want to make this dynamic because the above enum is auto generated. and should be remain same.
Is there a way to achieve this in a method itself i.e without creating any Class or adding extra Enum value in enum?
like : inv.Target = OTA_HotelInvCountNotifRQTarget.Null;
How can I do this?
The underlining values of an enum are int which can't be assigned to null.
If you still want to do so:
Add Null as an option to the enum:
public enum OTA_HotelInvCountNotifRQTarget
{
Null,
Test,
Production
}
Have your target a Nullable type:
Nullable<OTA_HotelInvCountNotifRQTarget> t = null;
//Or in a cleaner way:
OTA_HotelInvCountNotifRQTarget? t = null;
//And in your class:
public class YourType
{
public OTA_HotelInvCountNotifRQTarget? Target { get; set; }
}
public enum OTA_HotelInvCountNotifRQTarget
{
Null,
Test,
Production
}
also answewred here
How to set enum to null
Enum is enum. It value type and you can use
Nullable<OTA_HotelInvCountNotifRQTarget> or OTA_HotelInvCountNotifRQTarget? for represent "not set statement"
but if you still want user null as enum value try
public enum OTA_HotelInvCountNotifRQTarget
{
Null,
Test,
Production
}
Or using the "?" Operator for the variable:
public OTA_HotelInvCountNotifRQTarget? Target;
You have to change the assignment to:
inv.Target = null;
Why are we able to write
public int RetInt
{
get;set;
}
instead of
public int RetInt
{
get{return someInt;}set{someInt=value;}
}
What is the difference between the two?
This feature is called Auto implemented properties and introduced with C# 3.0
In C# 3.0 and later, auto-implemented properties make
property-declaration more concise when no additional logic is required
in the property accessors. They also enable client code to create
objects. When you declare a property as shown in the following
example, the compiler creates a private, anonymous backing field
that can only be accessed through the property's get and set
accessors.
class Customer
{
// Auto-Impl Properties for trivial get and set
public double TotalPurchases { get; set; }
public string Name { get; set; }
public int CustomerID { get; set; }
For your question
What is the difference between the two?
In your case, none. Since you are not doing anything while setting or retrieving the value, but suppose you have want to do some validation or want to perform other types of check then :
private int someInt;
public int RetInt
{
get
{
if (someInt > 0)
return someInt;
else
return -1;
}
set { someInt = value; } // same kind of check /validation can be done here
}
The above can't be done with Auto implemented properties.
One other thing where you can see the difference is when initializing a custom class type property.
If you have list of MyClass
Then in case of Normal property, its backing field can be initialized/instantiated other than the constructor.
private List<MyClass> list = new List<MyClass>();
public List<MyClass> List
{
get { return list; }
set { list = value; }
}
In case of Auto implemented property,
public List<MyClass> SomeOtherList { get; set; }
You can only initialize SomeOtherList in constructor, you can't do that at Field level.
How are these two different ?
There are different at least by 2 points:
In normal property you have to define a field before (someInt in your case)
In normal property you can set a breakpoint into the set/get modifiers, instead in auto property can not do that.
In other words: if you need "just property", use auto-properties, if you need more control over workflow (raise an event on set, debug, run other stuff inside), use "normal" properties.
These are auto implemented properties. Please see http://msdn.microsoft.com/en-us/library/bb384054.aspx for more info.
Basic reason why these were introduced was to reduce the overhead of programmer of creating a private variable like someInt which had little use than being used in a property.
Actually these aren't really different, in both cases you have a private field that corresponds to your property, but in the first case it is generated by the compiler and hidden.
If you need to use the variable behind the property quite often in your class, I think it's better to declare your property the old way (2nd one), because each time you will access it this will call the getter if you do it the "new" way.
If you only need it to be used from outside your class (or in most of cases), then you can go with the "new" way (1st one)
For ASP controls - let us say we are using button, is it possible to derive from BUTTON, a derived control and create new property called, say , ReferenceID (type say integer) and use that property.
I would like to have a unique id for the control other than the ID we are having
Yes, it is possible and the way you are thinking about it will work but keep in mind that you will have to keep track of the values assigned to this property in ViewState. What I mean is this (untested code):
public class CustomButtom : Button
{
public int ReferenceID {
get {
if(ViewState["ReferenceID"]!=null)
return int.Parse(ViewState["ReferenceID"].ToString());
return -1;
}
set {
ViewState["ReferenceID"]=value;
}
}
}