Assign enum as property c# - c#

I did not find any answer on the forum (however if there is one please let me know). I am writing backend structure for the ASP.NET MVC app and have some troubles with C# case.
I am wondering if such a solution is possible to happen (and need to do a following thing the way I described or similarly).
I will show the problem in the example below, because I do not know how to say it clearly in words.
I have defined Enum as following:
public enum myEnum
{
FirstOpt = 0,
SecondOpt= 1,
ThirdOpt = 2,
Unknown = -1,
}
Now, I want to assign myEnum in the different part of my solution in the custom attribute.
The attribute looks the following way:
public class SearchTypeAttribute : Attribute
{
public Type SType { get; set; }
public IEnumerable<object> SItems { get; set; }
}
Then I want to use it in the following way:
public class SomeClass
{
[Key]
public long Id { get; set; }
[SearchTypeAttribute(
SType = typeof(Enums.myEnum),
SItems = Enum.GetValues(typeof(Enums.myEnum))
)]
public string Type{ get; set; } // later to this item will be assigned string name of the assigned value
}
When I am doing this, the following error appears:
Error CS0655 'SItems' is not a valid named attribute argument because it is not a valid attribute parameter type
I was also trying to assign it as here:
public class SomeClass
{
[Key]
public long Id { get; set; }
[SearchTypeAttribute(
SType = typeof(Enums.myEnum),
SItems = Enums.myEnum // here !
)]
public string Type{ get; set; }
}
But I still have no idea what "Type" of property I should use in my SearchTypeAttribute, to be able to assign those values there.
I am doing this to be able to generate different types of fields in search bars in the views later.
Then in my code I want to assign the list of enum values or the specific enum to some variable, so I can then, operate on those values.
What types should I use to assign this type of data SItems ?
Is there other approach to do it ?
I am not yet really advanced in c#. Thank you for any help in advance.

An attribute is a compile-time thing. So you have to provide all the information at compile-time also. However Enum.GetValues will be executed at runtime, making it impossible to be used for an attribute. The only way to achieve this is by writing the possible enum-values directy into the attribute:
public class SomeClass
{
[Key]
public long Id { get; set; }
[SearchTypeAttribute(
SType = typeof(Enums.myEnum),
SItems = new[] { Enums.FirstOpt, Enums.SecondOpt, ...}
)]
public string Type{ get; set; }
}
Apart from this I can´t see why your SItems is of type IEnumerable<object>, when it obviously has only Enums-elements in it. It´s not even possible to use an IEnumerable on an attribute, only arrays of primitive types are allowed, as mentioned here. So SItems should be an Enums[].
Another approach is to rely on the attributes constructor and initialize SItems from there:
public class SearchTypeAttribute : Attribute
{
public SearchTypeAttribute(Type type)
{
this.SType = type;
this.SItems = Enum.GetValues(type);
}
}
Now simply use the attribute as follows:
[SearchTypeAttribute(typeof(Enums.myEnum))]
public string Type{ get; set; }

Related

Deleting variables from a local script and loading existing database data

Say we have a class PersonInfo
PersonInfo{
public int age = 10;
public int weight = 150;
}
and I uploaded this data to my Mongo DB.
Now, say I dont need wieght anymore, so my PersonInfo class looks like this:
PersonInfo{
public int age = 10;
}
But now, when I load from the Mongo DB it says,
"FormatException: Element 'weight' does not match any field or property of class PersonInfo."
How can I remove class variables without getting this error?
Thanks!
There are a few ways to solve this problem depending on what you're doing with your data.
By default as you've seen the driver will throw an exception if it can't deserializer all the bson document properties, this is so that we don't end up with some data loss.
The simplest approach is to add a ExtraElements property to your model that you're deserializing in to, this can be of either a BsonDocument or an IDictionary<string, object>.
public class PersonInfo
{
public ObjectId Id { get; set; }
public int Age { get; set; }
public BsonDocument ExtraElements { get; set; }
}
Alternately we can just ignore any extra elements that are in the document in a couple of ways.
The first one is adding a BsonIgnoreExtraElements attribute to our class
[BsonIgnoreExtraElements]
public class PersonInfo
{
public ObjectId Id { get; set; }
public int Age { get; set; }
}
Alternatively, we can create a class map for our PersonInfo in code by executing the following before running our query (this only needs to be executed once, ideally on application startup).
BsonClassMap.RegisterClassMap<PersonInfo>(map =>
{
map.AutoMap();
map.SetIgnoreExtraElements(true);
});
The next approach is if you want to apply to ignore extra elements across all or a range of types matching a predicate.
Here we're using a convention that we'll set up on application startup.
ConventionRegistry.Register("IgnoreExtraElements", new ConventionPack
{
new IgnoreExtraElementsConvention(true)
}, t => true);
The t => true predicate will apply the convention to all types.

JavaScriptSerializer How to Deserialize an identifier with space

I am having exactly the same problem as described here https://stackoverflow.com/questions/12565464/javascriptserializer-deserialize-an-identifier-with-space but as no one answered thought i'd try again,
API created by someone else in the form of
[{"AdvertId":"1234567","Price Original":"500","Sold":"False"}]
Application already uses a JavascriptSerilalization to populate the named properties on many other API's so do not want to change that really, but my class to hold this data can not have a property with a space in it "Price Original", and this can't be removed or replaced with an _ or something. Are there any methods that can be called to translate the string to something different?
Is there any solution to this or have I got to use JSON.net to deserialize, was some bits on DataContracts I read up on and these might be able to help but I can't seems to find out how to get this to work for my code, and would be nice to know that is possible without investigation this path.
Many thanks in advance
Sample Class
Class Sample
{
public int AdvertId { get; set; }
public string Price Original { get; set; }
public bool Sold { get; set; }
}
You can still use built-in types, but you'll need to use DataContractJsonSerializer instead of JavaScriptSerializer, and add the appropriate DataContract and DataMember attributes - the implementation is a bit different, but still pretty straightforward.
One thing - your Sold property is boolean, but your JSON sample has a string there - booleans are valid JSON types, so you can remove the quotes.
Some working code:
JSON:
[{"AdvertId":"1234567","Price Original":"500","Sold":false}]
C#:
var ser = new DataContractJsonSerializer(typeof(Sample[]));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(JSON))) {
Sample[] s = (Sample[])ser.ReadObject(ms);
}
[DataContract]
public class Sample {
[DataMember]
public int AdvertId { get; set; }
[DataMember(Name = "Price Original")]
public string PriceOriginal { get; set; }
[DataMember]
public bool Sold { get; set; }
}

Get custom property types using Reflection

Suppose I have a class (something like this):
public class User
{
public Guid Id { get; set;}
public DateTime CreationDate { get; set; }
public string Name { get; set; }
public UserGroup Group { get; set; }
}
Is there a way get all property types that are not part of the .NET Framework.
So in this case I want to get only UserGroup ? Is that possible ?
The best thing I can come up with is something like:
IEnumerable<Type> types = typeof(User).GetProperties().Where(p => !p.PropertyType.Namespace.StartsWith("System.")).Select(t => t.PropertyType);
But this looks like a hack-job. Sorry if dup, couldn't find anything like that, and sorry for the formatting, did my best.
I think what you have is probably reliable enough for what you want. However, from a flexibility/readability point of view maybe it would be better to define your own attribute type which you could apply at property level i.e.
public class User
{
public Guid Id { get; set; }
public DateTime CreationDate { get; set; }
public string Name { get; set; }
[CustomProperty]
public UserGroup Group { get; set; }
}
You could then use reflection to query all the properties which have this attribute. This would give you the ability to include/exclude any properties.
Sorry I forgot to mention that I can't modify the domain entities. (can't add an attribute).
You can use the MetadataType to add attributes to a base class e.g.
class UserMetadata
{
...
[CustomProperty]
public UserGroup Group { get; set; }
}
[MetadataType(typeof(UserMetadata)]
public class DomainUser : User
{
}
Reflection is always some kind of hacking, so yes, it FEELS like a hackjob.
But analyzing the entity, the class, will have to be done with reflection. So you are doing it the correct way.
One pitfall. You yourself are able to create your own types inside a namespace "System". That would mess up your search. You also could also analyze then Assembly of the property type, but then you have to know of all .NET assemblies, which is a big list.
What you have done is fine, you could do something like this however and make use of the Except method.
public static Type[] GetNonSystemTypes<T>()
{
var systemTypes = typeof(T).GetProperties().Select(t => t.PropertyType).Where(t => t.Namespace == "System");
return typeof(T).GetProperties().Select(t => t.PropertyType).Except(systemTypes).ToArray();
}
Your approach works. I would just throw in that you could also try to check the Assembly the type was defined in, and for example check if it was loaded from the global assembly cache.
bool wasLoadedFromAssemblyCache = typeof(T).Assembly.GlobalAssemblyCache;

Protocol Buffers and Typesafe Enums in C#

I'm trying to serialize some typesafe enums which I implemented like the answer to this question. When I serialize an object containing a reference to, say, FORMS (from the answer I linked), I'd like, upon deserialization, to restore the reference to the static field FORMS.
I have a solution but it seems kind crappy since I'd have to add it to any class that contained a typesafe enum. It pretty much just uses callbacks to store and retrieve the enum's value field:
public class SomethingContainingAnAuthenticationMethod
{
[ProtoMember(1)]
public int AuthenticationMethodDataTransferField { get; set; }
public AuthenticationMethod AuthenticationMethod { get; set; }
[ProtoBeforeSerialization]
public void PopulateDataTransferField()
{
AuthenticationMethodDataTransferField = AuthenticationMethod.value;
}
[ProtoAfterDeserialization]
public void PopulateAuthenticationMethodField()
{
AuthenticationMethod = AuthenticationMethod.FromInt(AuthenticationMethodDataTransferField);
}
}
Any other ideas would be much appreciated.
With the answer in the linked example, the simplest approach is probably:
[ProtoContract]
public class SomethingContainingAnAuthenticationMethod
{
[ProtoMember(1)]
private int? AuthenticationMethodDataTransferField {
get { return AuthenticationMethod == null ? (int?)null
: AuthenticationMethod.Value; }
set { AuthenticationMethod = value == null ? null
: AuthenticationMethod.FromInt(value.Value); }
}
public AuthenticationMethod AuthenticationMethod { get; set; }
}
which avoids an extra field and any callbacks. Something similar could also be done via a surrogate-type, but the above should work for most simple cases.
The mechanism for serializing an enum member is pretty simple:
[ProtoContract]
public class SomethingContainingAnAuthenticationMethod
{
[ProtoMember(1)]
public AuthenticationMethod AuthenticationMethod { get; set; }
}
And... that's about it. The minor gotcha sometimes (which might raise errors about not being able to find an enum with value) is the implicit-zero behaviour, but that is simply avoided:
[ProtoMember(1, IsRequired=true)]
public AuthenticationMethod AuthenticationMethod { get; set; }

ValueInjector not mapping property

I'm having trouble trying to get ValueInjector to map my objects correctly. This is the code I am using for the mapping:
public IEnumerable<CategoryDTO> FindCategories(IList<object[]> criteria)
{
IEnumerable<Category> categories = _categoryRepo.Find(criteria);
IEnumerable<CategoryDTO> categoriesDto = Mapper.Map<IEnumerable<Category>, IEnumerable<CategoryDTO>>(categories);
return categoriesDto;
}
the variable categories contains a property:
IEnumerable<Standard> Standards
This property contains two Standard objects in the instance I'm calling on. The problem is when I map from my Category to my CategoryDTO. CategoryDTO is defined as this:
public class CategoryDTO : AuditableDTO
{
public Guid CategoryId { get; set; }
public string Name { get; set; }
public string MachineName { get; set; }
public string Description { get; set; }
public IEnumerable<StandardDTO> Standards { get; set; }
}
After the mapping statement is run, and I investigate the contents of categoriesDto.Standards, I can see that it is null. I would have expected my Standards to have mapped, but I'm sure I'm missing something with ValueInjector. Probably something along the lines of telling it how to map Standard to StandardDTO. Any thoughts?
EDIT: I need to clarify, I'm using this http://valueinjecter.codeplex.com/wikipage?title=Automapper%20Simulation&referringTitle=Home
EDIT 2: Digging deeper, I can see that my Iesi.Collections.HashedSet is causing the issue. Categorys' Standards property are typed as Iesi.Collections.ISet, this is turned into the HashedSet. So I guess my real question is how do I check the property for that type and how can I map?
My guess would be that the Mapper.Map doesn't know to map one level deeper than the IEnumerable. Have you tried looping though the collection, mapping it at the Category, CategoryDTO level vs the IEnumerable level?

Categories