How to change class/property name? - c#

For example:
public class Car{
public string color {get; set;}
public int VINCode {get;set;}
}
Now if I call nameof(Car) it returns "Car"
[Name("something")]
public class Car{
[Name("something_else")]
public string color {get; set;}
public int VINCode {get;set;}
}
But how can I get nameof to return the value in the Name attribute rather than the name of the class or method. eg: nameof(Car) == "something" or nameof(Car.color) == "something_else".
the problem:
var modelState = JsonConvert.DeserializeObject<Dictionary<string, List<string>>>(data);
var departmentViewModels = modelState[nameof(DepartmentListView.DepartmentsViewModels)][0];
var departmentTypes = modelState[nameof(DepartmentListView.DepartmentsViewModels)][0];
fixing for that:
var modelState = JsonConvert.DeserializeObject<DepartmentListView>(data);
var departmentViewModels = modelState.DepartmentsViewModels;
var departmentTypes = modelState.DepartmentTypes;
Serialization of this:
public class DepartmentListView
{
public IEnumerable<DepartmentViewModel> DepartmentsViewModels { get; set; }
public IEnumerable<DepartmentType> DepartmentTypes { get; set; }
}
will be:
departmentsViewModel : [], departmentTypes : [] (with lowercase)
I know I can change that lowercase serialization with JsonProperty, but I thought that I will can change the name of class or property...

I'm afraid you cannot do it with nameof.
But if you want to get the value of a CustomAttribute you can try this:
// I assume this is your Name class
public class Name: Attribute
{
public string Data { get; }
public Name(string data) { Data = data; }
}
Then you can
// Will return "something"
var classAttrData = ((Name) typeof(Car).GetCustomAttribute(typeof(Name))).Data;
// Will return "something_else"
var fieldAttrData = ((Name) typeof(Car).GetField(nameof(Car.color)).GetCustomAttribute(typeof(Name))).Data;

It's look like you are asking about your attempted solution rather than your actual problem.
The solution to get new name of class / property:
Create your class with DisplayNameAttribute as follow:
[DisplayName("something")]
public class Car
{
[DisplayName("something_else")]
public string color { get; set; }
public int VINCode { get; set; }
}
To get your class attribute name:
var attributes = typeof(Car) // type declaration
.CustomAttributes.FirstOrDefault() // first item of collection that contains this member's custom attributes like [DisplayName("something")]
?.ConstructorArguments.FirstOrDefault() // first item of structure collecion
.Value; // value as string - "something"
Similarly to the property name, you only need to get its type first
var attribute = typeof(Car).GetProperty(nameof(Car.color)) // ...
instead of
var attribute = typeof(Car) // ...

Related

Automapper: update collection

Code:
[Fact(DisplayName = "")] public void Test1()
{
var definition = new Definition
{
Hash = "hash1",
Link = "link1",
Name = "name1"
};
var view = new View
{
Hash = "hash2",
Id = Guid.Parse("ab8a6aac-532d-43af-aa0a-3781f0da3d96"),
Link = null,
Name = "name2"
};
var views = new List<View>
{
view
};
var definitions = new List<Definition>
{
definition
};
var collectionsMapping =_mapper.Map(definitions, views);
var simpleMapping =_mapper.Map(definition, view);
}
Profile settings:
CreateMap<ReadFileDefinition, StandardFileView>();
Destination class:
public class View
{
public Guid? Id{get;set;}
public string? Name { get; init; }
public string? Hash { get; set; }
public string? Link { get; set; }
}
Source class:
public class Definition
{
public string Name { get; set; }
public string Hash { get; set; }
public string Link { get; set; }
}
As you can see, class 'Definition' is missing property 'Id'. When you try to update property 'Id' for the collection 'List<View>'(see 'collectionsMapping'), it is always null.
But for 'simpleMapping' it works fine and 'Id' keep value from destination object.
(collectionsMapping result)
(simpleMapping result)
Question: How do i update property 'Id' for each collection member so that it stays from destination collection views?
Thx.
Mapping a single item will use the given destination instance and will not touch any unmapped properties (here the Id property).
Mapping a collection will create a new destination item for each source item and there you have the given default value from the class definition for any unmapped property.
You may want to customize the mapping to set the Id property in this case.

How to automatically include type information when serializing?

Is it possible to specify that I always want type-information in the json object when serializing a property in an class?
(Ideally with Newtonsoft).
I'm thinking something like this:
public abstract class Value {...}
public class BigValue : Value {...}
public class SmallValue : Value {...}
public class ValueContainer
{
[JsonSetting(TypenameHandling = TypenameHandling.All)] // <--- Something like this?
public Value TheValue { get; set; }
}
I am aware that I could specify this behavior when doing the parsing with a custom converter.
But I want to include the typeinformation every time objects of this type is serialized, without manually having to specify which serialization options to use.
Newtonsoft.Json's JsonPropertyAttribute has TypeNameHandling property which you can set:
public class Root
{
[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
public Base Prop { get; set; }
}
public class Base
{
public int IntProp { get; set; }
}
public class Child:Base
{
}
// Example:
var result = JsonConvert.SerializeObject(new Root
{
Prop = new Child()
});
Console.WriteLine(result); // prints {"Prop":{"$type":"SOAnswers.TestTypeNamehandling+Child, SOAnswers","IntProp":0}}

Mongo C#Driver:Deserialize BsonArray

I have a document in mongodb that is structured similar to this:
{
"_id":xxxxx,
"business":[{
"subBusiness":[{
"subBusinessName":"Abusiness",
"a":"aaaa"
},{
"subBusinessName":"Bbusiness",
"b":"bbbbb",
"c":"ccccc"
}]
}]
}
how to make a mapping class to serialize this document?
I also have a class defined to represent dimensions (the sub document from above)
class STObject{
[BsonId]
public ObjectId id{get;set;}
[BsonElement("business")]
public List<Business> BusinessList{get;set;}
}
class Business {
[BsonElement("subBusiness")]
public List<SubBusiness> SubBuiness { get; set; }
}
[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(CSSubBusiness),typeof(ApproSubBusiness))]
public class SubBusiness {
[BsonElement("subBusinessName")]
public string SubBusinessName{get;set;}
}
public class AsubBusiness:SubBusiness{
[BsonElement("a")]
public string A{get;set;}
}
public class BsubBusiness:SubBusiness{
[BsonElement("b")]
public string B{get;set;}
[BsonElement("c")]
public string C{get;set;}
}
how to query element "b" in class STObject?
In order to deserialize class hierarchy, document should contain type discriminator field, which tells which type of subclass should be instantiated. By default this field has name _t. But if you already have documents with schema as above and can't change it, then you should override discriminator convention which is used by Mongo.
Looks like you can use subBusinessName field as type discriminator for sub business types. In order to do that, you should remove this field from base type:
[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(AsubBusiness), typeof(BsubBusiness))] // btw check types
public class SubBusiness
{
}
And you should provide discriminator values for subtypes:
[BsonDiscriminator("Abusiness")] // provide discriminator value here
public class AsubBusiness : SubBusiness
{
[BsonElement("a")]
public string A { get; set; }
}
[BsonDiscriminator("Bbusiness")]
public class BsubBusiness : SubBusiness
{
[BsonElement("b")]
public string B { get; set; }
[BsonElement("c")]
public string C { get; set; }
}
And final step - create custom convention to make mongo look on this discriminator field for instantiating correct sub class type:
public class SubBusinessDiscriminatorConvention : IDiscriminatorConvention
{
public string ElementName
{
get { return "subBusinessName"; }
}
public Type GetActualType(BsonReader bsonReader, Type nominalType)
{
var bookmark = bsonReader.GetBookmark();
bsonReader.ReadStartDocument();
var actualType = nominalType;
if (bsonReader.FindElement(ElementName))
{
var discriminator = (BsonValue)BsonValueSerializer.Instance.Deserialize(bsonReader, typeof(BsonValue), null);
actualType = BsonSerializer.LookupActualType(nominalType, discriminator);
}
bsonReader.ReturnToBookmark(bookmark);
return actualType;
}
public BsonValue GetDiscriminator(Type nominalType, Type actualType)
{
var classMap = BsonClassMap.LookupClassMap(actualType);
return classMap.Discriminator;
}
}
Now set this convention for your base type serialization:
BsonSerializer.RegisterDiscriminatorConvention(typeof(SubBusiness),
new SubBusinessDiscriminatorConvention());
And you can serialize and deserialize documents in your exact format.
UPDATE: Querying:
var collection = test.GetCollection<STObject>("collectionName");
var sto = collection.FindOne(Query.EQ("_id", new ObjectId("xxxxx")));
var businessList = sto.BusinessList.FirstOrDefault();
var bsub = businessList.SubBuiness.OfType<BsubBusiness>().FirstOrDefault();
var b = bsub.B; // returns bbbbb

Dynamicly add items to ListBox via Attributes

i've got 3 classes (all deriving from the same base class) and i have to dynamicly fill a ListBox with the Property-Names.
I've tried like this
class Test : TestBase {
[NameAttribute("Name of the Person")]
public string PersonName { get; set; }
private DateTime Birthday { get; set; }
[NameAttribute("Birthday of the Person")]
public string PersonBDay {
get {
return this.bDay.ToShortDateString();
}
}
}
...
[AttributeUsage(AttributeTargets.Property)]
public class NameAttribute : Attribute {
public string Name { get; private set; }
public NameAttribute(string name) {
this.Name = name;
}
}
Is there a possibility to look in my object for all properties which has the attribute NameAttribute and get the string form the Name property of NameAttribute?
You can inspect each property from Type.GetProperties and then filter the ones that have the required attribute with the MemberInfo.GetCustomAttributes method.
With a little bit of LINQ, this would look like:
var propNameTuples = from property in typeof(Test).GetProperties()
let nameAttribute = (NameAttribute)property.GetCustomAttributes
(typeof(NameAttribute), false).SingleOrDefault()
where nameAttribute != null
select new { Property = property, nameAttribute.Name };
foreach (var propNameTuple in propNameTuples)
{
Console.WriteLine("Property: {0} Name: {1}",
propNameTuple.Property.Name, propNameTuple.Name);
}
By the way, I also recommend declaring the attribute to be single-use only with AllowMultiple = false in the AttributeUsage decoration.

C# help with Extension Method - Converting collection to another type

I want to convert from
public class Party
{
public string Type { get; set; }
public string Name { get; set; }
public string Status { get; set;}
}
and convert to
public class Contact
{
public string Type { get; set; }
public string Name { get; set; }
public string Status { get; set;}
public string Company {get;set;}
public string Source {get;set;}
}
I tried using this extension method
public static class EnumerableExtensions
{
public static IEnumerable<TTo> ConvertTo<TTo, TFrom>(this IEnumerable<TFrom> fromList)
{
return ConvertTo<TTo, TFrom>(fromList, TypeDescriptor.GetConverter(typeof(TFrom)));
}
public static IEnumerable<TTo> ConvertTo<TTo, TFrom>(this IEnumerable<TFrom> fromList, TypeConverter converter)
{
return fromList.Select(t => (TTo)converter.ConvertTo(t, typeof(TTo)));
}
}
I get this error TypeConverter is unable to convert 'Party' to 'Contact'
var parties = new List<Party>();
parties.Add(new Party { Name = "name 1", Status = "status 1" });
parties.Add(new Party { Name = "name 2", Status = "status 2" });
var results = parties.ConvertTo<Contact, Party>().ToList();
What am I missing here?
There is no direct conversion between the type Party and the Type contact (polymorphic or inheritance based).
You need to implement a TypeConverter for your types so that .NET knows how to convert between those two types:
MSDN - TypeConverter Class
MSDN - How to Implement a TypeConverter
Once you create your TypeConverters, you have to decorate your two classes with the TypeConverterAttribute so that the Framework can get an instance of your TypeConverter at Runtime:
public class PartyTypeConverter : TypeConverter
{
// Implementation
}
[TypeConverter(typeof(PartyTypeConverter)]
public class Party
{
public string Type { get; set; }
public string Name { get; set; }
public string Status { get; set; }
}
You could also attempt to mimic the (what I'm guessing) is the desired behavior using LINQ (even though you'll lose the generic abilities):
var contacts = parties.Select(p => new Contact {
Type = p.Type,
Name = p.Name,
Status = p.Status
});
here is a slightly different way, though at its core it still about simply copying member values from one object to another
add this to your Contact class
public static explicit operator Contact(Party p)
{
return new Contact
{
Type = p.Type,
Name = p.Name,
Status = p.Status
};
}
then convert like this:
List<Party> parties = new List<Party>();
parties.Add(new Party { Name = "Foo", Status = "Bar" });
parties.Select<Party, Contact>(p => (Contact)p)
you may want to enclose last bit into some extension method, but I don't see a point...

Categories