How to get a value of a property - c#

Hello people i'm with the next problem:
public class Document
{
public Header Header {get;set;}
public Footer Footer{get;set;}
public string Text{get;set;}
public string Description{get;set;}
public int NumberOfPages{get;set;}
}
public class Header
{
public int Id{get;set;}
public string Text{get;set;}
}
public class Footer
{
public int Id{get;set;}
public string Text{get;set;}
}
Imagine i have this domain, i will like to copy all the primitive properties of Document and the ones that aren't primitive, such as Header and Footer i would like just the text.
I have the next code just to copy the properties which are primitive:
public static List<DataPropertyReport> GetPrimitiveProperties<T>(T entity)
{
var properties = entity.GetType().GetProperties();
List<DataPropertyReport> info = new List<DataPropertyReport>();
foreach (var property in properties)
{
Object value = property.GetValue(entity, null);
Type type = value != null ? value.GetType() : null;
if (type != null &&
(type.IsPrimitive ||
type == typeof(string) ||
type.Name == "DateTime"))
{
var name = property.Name;
info.Add(new DataPropertyReport(name, value.ToString(), 1));
}
}
return info;
}

You could override ToString() on the non-primitive types and just call that overload:
public class Header
{
public int Id { get; set; }
public string Text { get; set; }
public override string ToString()
{
return Text;
}
}
public class Footer
{
public int Id { get; set; }
public string Text { get; set; }
public override string ToString()
{
return Text;
}
}

Related

Model with property that can be an any value type

I have a controller method that gets the FilterState model.
That model contains a list of Filter models, that contains Value property, which can be any of a value type (int, string, datetime etc).
How I can write this class and determine the property type that came to me from front end?
[HttpGet]
public async Task<GridResultViewModel<ItemGridViewModel>> GetFiltered(int modelId,
[FromQuery] FilterState filterState)
{
...
}
public class FilterState
{
public int Skip { get; set; }
public int Take { get; set; }
public IEnumerable<Filter> Filters { get; set; }
}
public class Filter
{
public string Operator { get; set; }
public string Field { get; set; }
public ??? Value { get; set; } // this can be string, int, datetime etc.
}
If I made Value property as object or dynamic type, is always null.
I'm using Angular 11 on frontend.
public string Value { get; set; } = "str12";
object CheckType(string value)
{
return
int.TryParse(value, out int intVal) ? intVal :
DateTime.TryParse(value, out DateTime datetimeVal) ? datetimeVal :
value;
}
var result = CheckType(Value);
if (result is int)
{
}
if (result is string)
{
}

Match names in list with elements in class

I wonder if there's any way to match the names in a list with the elements in a class:
I have a class:
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
and a List: List<exampleClass> EnfSist
So that's the way the list is made. Now I would like to know how to match or identify the string inside "name" from my list. To match this class:
tbl_sistematicas b = new tbl_sistematicas
{
ap_enf_id_enfermedad = Convert.ToInt32(EnfSist[0].value),
ap_pac_inicio = Convert.ToInt32(EnfSist[1].value),
ap_pac_inicio_periodo = Convert.ToInt32(2].value),
ap_pac_duracion = Convert.ToInt32(EnfSist[3].value),
ap_pac_duracion_periodo = Convert.ToInt32(EnfSist[4].value),
ap_pac_tratamiento = EnfSist[5].value
};
Once being able to match the same names I won't have to specify each index of every element in the list. The elements in the list have the same name as in the table. Not all elements of the class are being used.
I have something like this: tbl_sistematicas bh = EnfSist.FindAll(x => x.name == bh.?????? );
If I understand the question, you can do this using something like automapper or ValueInjector
An example using ValueInjector
void Main()
{
List<exampleClass> EnfSist = new List<exampleClass>();
EnfSist.Add(new exampleClass { name = "ap_enf_id_enfermedad", value = "12" });
EnfSist.Add(new exampleClass { name = "apap_pac_inicio" , value = "34" });
// etc
tbl_sistematicas b = new tbl_sistematicas();
b.InjectFrom<MyInjection>(EnfSist);
}
public class MyInjection : KnownSourceValueInjection<List<exampleClass>>
{
protected override void Inject(List<exampleClass> source, object target)
{
foreach(var entry in source)
{
var property = target.GetProps().GetByName(entry.name, true);
if (property != null)
property.SetValue(target, Convert.ChangeType(entry.value, property.PropertyType));
}
}
}
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
public class tbl_sistematicas
{
public int ap_enf_id_enfermedad { get; set; }
public int apap_pac_inicio { get; set; }
public int ap_pac_inicio_periodo { get; set; }
public int ap_pac_duracion { get; set; }
public int ap_pac_duracion_periodo { get; set; }
public string ap_pac_tratamiento { get; set; }
}
Note, this will throw an exception if the value can not be converted to an int

Efficient way to access a property of a class by the string name

I want access to a property value by its name. The only way i know it's by reflection with a code like this:
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
Are there others ways to do it (using ex. codegen, etc.)?
The only way I know it's by reflection with a code like this:
Reflection is one way, it's also expensive (so I've heard), so you create a cache to speed up multiple property looks ups (this is what asp.net-mvc does). Something like (totally example code):
private static Dictionary<PropertyInfoKey, PropertyInfo> propertyCache =
new Dictionary<PropertyInfoKey, PropertyInfo>()
private class PropertyInfoKey : IEquatable
{
public PropertyInfoKey(string fullName, string propertyName)
{
FullName = fullName;
PropertyName = propertyName
}
public string FullName { get; private set; }
public string PropertyName { get; private set; }
public bool Equals(PropertyInfoKey other)
{
if ( ..// do argument checking
var result = FullName == other.FullName
&& PropertyName == other.PropertyName;
return result;
}
}
public static bool TryGetPropValue<T>(T src,
string propName,
out object value)
where T : class
{
var key = new PropertyInfoKey(
fullName: typeof(T).FullName,
propertyName: propName
);
PropertyInfo propertyInfo;
value = null;
var result = propertyCache.TryGetValue(key, out propertyInfo);
if (!result)
{
propertyInfo = typeof(T).GetProperty(propName);
result = (propertyInfo != null);
if (result)
{
propertyCache.Add(key, propertyInfo)
}
}
if (result)
{
value = propertyInfo.GetValue(src, null);
}
return result;
}
(*maybe you could use a HashSet instead since PropertyInfoKey could technically hold the PropertyInfo as well, and it's implementing IEquatable)
OR....
If you are doing this because you have a lot of classes that share similar properties but are completely different and unrelated...
public interface IName
{
public string Name { get; }
}
public class Car : IName
{
public string Name { get; set; }
public string Manufacturer { get; set; }
}
public class Animal : IName
{
public string Name { get; set; }
public string Species { get; set; }
}
public class Planet : IName
{
public string Name { get; set; }
public string ContainSystem { get; set; }
}
Then you can
public static string GetName(this IName instance)
{
return instance.Name;
}

AutoMapper with more than one destination type

I am trying to map a source type to two destination types by using AutoMapper:
public class Source
{
public string Value1 { get; set; }
public string Value2 { get; set; }
public Source[] Values { get; set; }
}
public interface IDest
{
}
public class DestinationSimple : IDest
{
public string Value1 { get; set; }
}
public class DestinationComplex : IDest
{
public string Value2 { get; set; }
public IDest[] Values { get; set; }
}
Destination type to map to should be based on the property values in the source type. If Value1 in Source is not null, destination type should be DestinationSimple. Otherwise destination type should be DestinationComplex.
Which way is the best to proceed? I have tried to use a custom type converter, but I couldn't get it to work because I didn't know how to handle the Values property.
Here's one way you could do this using a custom type converter:
public class IDestConverter : TypeConverter<Source, IDest>
{
protected override IDest ConvertCore(Source src)
{
IDest result = null;
if (src.Value1 != null)
{
result = new DestinationSimple
{
Value1 = src.Value1
};
}
else
{
result = new DestinationComplex
{
Value2 = src.Value2,
Values = Mapper.Map<IDest[]>(src.Values)
};
}
return result;
}
}
Usage:
Mapper.CreateMap<Source, IDest>()
.ConvertUsing<IDestConverter>();

Classes with the same interface but different types for a property

I would like to have this kind of design :
public interface IDifferentTypes
{
}
public class IntegerType : IDifferentTypes
{
public int value { get; set; }
}
public class StringType : IDifferentTypes
{
public string value { get; set; }
}
public class DateTimeType : IDifferentTypes
{
public DateTime value { get; set; }
}
but with the property 'value' defined in the interface.
So I can call something like that :
IDifferentTypes someInt = GetSomeInt(); // GetSomeInt() returns a IntegerType object
Assert.AreEqual(5, someInt.value);
IDifferentTypes someString = GetSomeString(); // GetSomeString() returns a StringType object
Assert.AreEqual("ok", someString.value);
Problem is that the type of value is different for each implementation, what is the best way to deal with that?
You could define a generic interface (but it will have to be a property, or, more strictly, it can't be a field):
public interface IHasValue<T> {
T Value { get; }
}
Where T is the type, a placeholder, if you will, and you can do:
public class HasStringValue : IHasValue<string> {
public string Value { get; private set; }
}
Use generics if you can:
var someInt = GetSomeInt();
Assert.AreEqual(5, someInt.Value);
var someString = GetSomeString();
Assert.AreEqual("ok", someString.Value);
// ...
public interface IDifferentTypes<T>
{
T Value { get; set; }
}
public class IntegerType : IDifferentTypes<int>
{
public int Value { get; set; }
}
public class StringType : IDifferentTypes<string>
{
public string Value { get; set; }
}
public class DateTimeType : IDifferentTypes<DateTime>
{
public DateTime Value { get; set; }
}
interface IDifferentTypes
{
Object Value { get; set; }
}
class StringType : IDifferentTypes
{
string _value;
public Object Value
{
get
{
return _value;
}
set
{
_value = value as string;
}
}
}
But this means that every time you use StringType.Value you're going to need to recast it. You may want to also expose a public accessor of the specific type. You also may want to add some protections against assigning the wrong type:
class StringType : IDifferentTypes
{
public String StringProperty { get; set; }
public Object Value
{
get
{
// works with any type that can auto cast to `Object`
return StringProperty;
}
set
{
// Optional
if( typeof(string) != value.GetType() )
{
throw new MyException();
}
// works for any nullable type
StringProperty = value as string;
// OR
// throws an exception if conversion fails
StringProperty = (string)value;
}
}
}

Categories