DisplayAttribute - How can I set a default Resource? - c#

I have a poco class Product
public class Product
{
public int Id {get;set;}
[RequiredEx]
public string ProductName {get;set;}
}
the RequiredEx attribute ist just a little wrapper around RequiredAttribute (System.ComponentMode.DataAnnotations` so I don't have to specify the Resource type / name every time.
public class RequiredExAttribute : System.ComponentModel.DataAnnotations.RequiredAttribute
{
public RequiredExAttribute()
{
this.ErrorMessageResourceType = typeof(ModelResources);
this.ErrorMessageResourceName = "ErrorMessage.Required";
}
}
Now I want to decorate my property with the Display attribute
[Display(ResourceType=typeof(ModelResources), Name="Product.ProductName")]
public string ProductName { get; set; }
In this case I can't just inherit from DisplayAttribute because it is sealed. Is there any chance for me not to have to type ResourceType=typeof(ModelResources) everytime I use this Attribute?

Since the attribute is sealed, and isn't part of a more complex OO model (the base class is just Attribute, and there are no interfaces implemented), I can't see that you have any options available to you here. Basically, I expect the answer is simply: "you will heed to specify the ResourceType every time".

If you're only using the Name property of the DisplayAttribute you can achieve this by inheriting from the (older) DisplayNameAttribute, which is not sealed:
using System.Resources;
namespace System.ComponentModel
{
public class LocalisedDisplayNameAttribute
: DisplayNameAttribute
{
readonly ResourceManager m_resourceManager;
readonly string m_resourceName;
public LocalisedDisplayNameAttribute(ResourceManager resourceManager,
string resourceName)
: base()
{
m_resourceManager = resourceManager;
m_resourceName = resourceName;
}
public override string DisplayName
{
get { return m_resourceManager.GetString(m_resourceName); }
}
}
}
You can then set up display attributes for your common string resources:
public class DisplayBizAttribute
: LocalisedDisplayNameAttribute
{
public DisplayBizAttribute(string resourceName)
: base(StringsBiz.ResourceManager, resourceName)
{
}
}
public class DisplayWebAttribute
: LocalisedDisplayNameAttribute
{
public DisplayBizAttribute(string resourceName)
: base(StringsWeb.ResourceManager, resourceName)
{
}
}
And then you can localise your property display names very easily, with string literals or constants:
[DisplayBiz("ProductName")]
public string ProductName { get; set; }
[DisplayBiz(StringNames.PHONE_NUMBER)]
public string ProductName { get; set; }
[DisplayWeb("EmailAddress")]
public string EmailAddress { get; set; }
Update
This can be improved by declaring an enum in each attribute class, and changing the constructor, or adding a new one:
public class DisplayBizAttribute
: LocalisedDisplayNameAttribute
{
public enum Name
{
PhoneNumber,
ProductName,
}
public DisplayBizAttribute(Name resourceName)
: base(StringsBiz.ResourceManager, resourceName.ToString())
{
}
}
Now you don't have to use hard-coded strings.
[DisplayBiz(DisplayBiz.Name.ProductName)]
public string ProductName { get; set; }
This is something you do a lot, so I like to add a using to shorten the enum:
using Biz = System.ComponentModel.DisplayBiz.Name;
...
[DisplayBiz(Biz.PhoneNumber)]
public string PhoneNumber { get; set; }

Related

How to get members of abstract class using reflection?

I have following:
var type = typeof(ExampleClass);
public abstract class ExampleClass
{
public string Name { get; set; }
public abstract class InternalExampleClass
{
public string InternalName { get; set; }
}
}
How can I get the value of Name, InternalName?
I tried to use type.GetFields() but it doesn't return InternalName
help me, please
I can't answer all points of your question. But I can give you an idea how to start.
You don't have access to constants, but there is a workaround. First, you need an instance of your abstract class in order to use reflection. Since you can't create an object of an abstract class, you need a class which inherits it. This class contains properties set to the value of your constants.
public class InheritedReportAPI : ReportAPI
{
public string constName { get; } = ReportAPI.Name;
public string constSignatureBase { get; } = ReportAPI.SignatureBase;
public string constEventsReportsDeleted { get; } = ReportAPI.Events.ReportsDeleted;
}
Then you can use Reflection to get names and/or values of these properties.
var inheritedReportApi = new InheritedReportAPI();
var propertyList = inheritedReportApi.GetType().GetProperties();
foreach(var property in propertyList)
System.Console.WriteLine($"{property.Name}: {property.GetValue(inheritedReportApi)}");
The result:
constName: reports
constSignatureBase: /report/reports
constEventsReportsDeleted: reports_deleted

Get attribute information from inheriting class, inside static function

I have a situation where I need to get the value on a property on an attribute (decorator) applied to a class. That class that is decorated, is inheriting from an abstract class. It is this abstract class that needs to get the attribute information, but it needs to do so inside a static function.
I cannot post the exact scenario, but here is a terrible example that could do without attributes, but please work with it as it is:
public class VehicleShapeAttribute : Attribute
{
public string Shape { get; }
public VehicleShapeAttribute(string shape)
{
Shape = shape;
}
}
public abstract class Vehicle
{
public string Brand { get; set; }
public string Model { get; set; }
public string Colour { get; set; }
public static string GetVehicleShape()
{
//return value from the attribute, from this static function. CANT DO THIS HERE
return AnyInheritingClass.VehicleShapeAttribute.Shape;
}
}
[VehicleShape("sedan")]
public class VauxhaulAstraSedan : Vehicle
{
//calling GetVehicleShape() on this class should automatically return "sedan"
}
Is this possible?
This is a bad example but I cannot post the actual code
Make the method non-static and resolve the runtime type with this.GetType():
public abstract class Vehicle
{
public string Brand { get; set; }
public string Model { get; set; }
public string Colour { get; set; }
public string GetVehicleShape()
{
var attribute = Attribute.GetCustomAttribute(this.GetType(), typeof(VehicleShapeAttribute)) as VehicleShapeAttribute;
if(attribute is VehicleShapeAttribute){
return attribute.Shape;
}
return null;
}
}
For a static version, you'll need to accept a Vehicle parameter whose type you can then inspect:
public static string GetVehicleShape(Vehicle vehicle)
{
var attribute = Attribute.GetCustomAttribute(vehicle.GetType());
// ...
Alternatively (and I'm just copy/pasting Mathias' code into another form syntactically here) if you really need to have the method static because you don't want to create an instance, you can add the following method to your attribute code (or any other static class, but I like to put it there with the attribute):
public static string GetFrom<T>()
{
return GetFrom(typeof(T));
}
public static string GetFrom(Type t)
{
var attribute = Attribute.GetCustomAttribute(t, typeof(VehicleShapeAttribute)) as VehicleShapeAttribute;
if(attribute is VehicleShapeAttribute){
return attribute.Shape;
}
return null;
}
Then you could write code like:
var shape = VehicleShapeAttribute.GetFrom<VauxhaulAstraSedan>();
or
var shape = VehicleShapeAttribute.GetFrom(typeof(VauxhaulAstraSedan));
or even
var vehicle = new VauxhaulAstraSedan();
var shape = VehicleShapeAttribute.GetFrom(vehicle.GetType());

WPF - Instance subclass from superclass

I'm doing and WPF application and I have a ViewModel that I use in several Views and in DataGrids.
Now I have another View that requires an extended or decorated version of that ViewModel. So I decided to go for inheritance in this way:
public class StandardViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class ExtendedViewModel : StandardViewModel
{
public string Email { get; set; }
}
However, I want to decorate and existing instance of the StandardViewModel. Specifically the selected object in the DataGrid so it can be passed into the other View.
The new View needs access to the properties of both classes (the Email and the FirtsName and LastName)
So I'm thinking of ways to creating a constructor for my ExtendedViewModel.
My idea is to copy the base instance directly.
Is this correct?
And efficient?
Is there any other way of doing it?
public class ExtendedViewModel : StandardViewModel
{
public string Email { get; set; }
public ExtendedViewModel(StandardViewModel base)
{
this = base
}
}
Edit
I'm doing this for not only one but several classes. And they do not have only two properties so I'm trying to avoid copying the values one by one.
Finally I'll avoid using inheritance and I'll create a new class, expose the base class and subscribe to INotifyPropertyChanged as described here and here.
This way I'll be able to have properties that depend on the Base ViewModel updated as done with FullName below.
The resulting ViewModel will look like:
public class ExtendedViewModel
{
public StandardViewModel Base { get; set; }
public string Email { get; set; }
public string FullName {
get => Base.FirstName + Base.LastName;
}
public ExtendedViewModel(StandardViewModel base)
{
Base = base
Base.PropertyChanged += BaseChanged
}
private void BaseChanged(object sender, PropertyChangedEventArgs e)
{
// Here check if FirstName or LastName changed and
RaisePropertyChanged("FullName");
}
}
In the view I will bind directly to Email or to Base.FirstName.
In oversimplified terms a decorator owns an instance of the class it decorates and delegates functionality existing in the owned class to that class, while adding new functionality uncoupled from the owned class instance.
public class StandardViewModel
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
public class ExtendedViewModel : StandardViewModel
{
private StandardViewModel _standard;
public ExtendedViewModel (StandardViewModel standard)
{
if (standard.GetType() != typeof(StandardViewModel )) {
throw new ArgumentException ("Expected a non derived standard view model", nameof(standard));
}
_standard = standard;
}
public string Email { get; set; }
public override string FirstName {
get => _standard.Firstname;
set => _standard.Firstname = value;
}
public override string LastName {
get => _standard.LastName;
set => _standard.LastName = value;
}
}

Get property default value on class initialize

Let's say we have some class CarsBase
public class CarsBase
{
public string DisplayName { get; set; }
}
Then we have some other class Toyota
public class Toyota : CarsBase
{
public EngineType EngineType { get; set; }
}
Then we are initializing our class instance by using object initializer like so:
var myVar = new Toyota()
{
// DisplayName = "", ← We could do this by our hands, but can it be done automatically?
EngineType = EngineType.UZ
}
Question: Is there any way to fill CarsBase's DisplayName property automatically on object initialize?
Like, if I had several more car classes (BMW, Suzuki , etc.), each is extending CarsBase and as a result have DisplayName property in each class.
This sounds like something that should be done in a constructor.
public class Toyota : CarsBase
{
public Toyota() : base()
{
base.DisplayName = "Toyota";
}
public EngineType EngineType { get; set; }
}
Another option, however less recommended, instead of getting/setting a DisplayName in the same sense, the base class could be changed to use reflection retrieve the classname and use that as the display name:
public class CarsBase
{
public string DisplayName
{
get
{
return this.GetType().Name;
}
}
}
This method should just return the "Toyota" from the classname, however would prevent usage of spaces or other special characters. Reflected code such as this also has a tendency to be slower.
Create a constructor to pass dispay name (or other parameters as required)-
Toyota(string displayName)
{
DisplayName = displayName;
EngineType = EngineType.UZ;
}
Then you can call like this-
new Toyota("some display name");
Just set the property value in the constructor. Something like this:
internal class Program
{
private static void Main(string[] args)
{
Toyota t = new Toyota() { EngineType = new EngineType() };
Console.WriteLine(t.DisplayName);
Console.ReadLine();
}
}
public class CarsBase
{
public string DisplayName { get; set; }
}
public class Toyota : CarsBase
{
public EngineType EngineType { get; set; }
public Toyota()
{
// set the default Display Name
// that way you don't have to set it everytime
this.DisplayName = "Oh what a feeling!";
}
}
public class EngineType { }
Yes, it can be done during the initialization stage of object where constructor is fired . I have created two classes
* one for holding enum constant value for engine_Types --> EngineType
one for explaining the inheritance,Constructor-Chaining, creating an instance of class which is an object----> CarsBase
[pre]
namespace stacketst
{
public class CarsBase
{
public string DisplayName { get; set; }
public CarsBase()
{
//called when CarBase object is initialized
DisplayName = "Base Car";
}
}
public class Toyota : CarsBase
{
//getters , setters called as properties in C#
public int number_of_wheels { get; set; }
public double fuel_capacity { get; set; }
public string engine_type { get; set; }
public Toyota() //called when an instance of Toyota is created
{
//assinging value to this property calls set
fuel_capacity = 4.2;
number_of_wheels = 4;
engine_type = EngineType.name_engines.UZ.ToString();
}
}
public class TestClass
{
static void Main()
{
//when below line is executed,constructor is fired & the initialization of variable inside constructor takes place
var myVar = new Toyota();
Console.WriteLine(myVar.DisplayName);
}
}
}
namespace stacketst
{
public class EngineType
{
//enums to hold constants, common for any Car Class
public enum name_engines
{
V12, V10, V8, V6, UZ
};
}
}
[/pre]

AutoMapper isn't recognizing profile-specific prefixes

I'm trying to use AutoMapper to take data from a class that has prefixes before property names and map it to a second class that doesn't have those prefixes. However, I don't necessarily want it to always strip out that prefix: I just want it to do it for this particular mapping.
My source class looks like this:
public class AdvancedSearchFilterDataModel
{
// ....
public string ServiceMeterNumber { get; set; }
// ....
}
My destination class looks like this:
[DataContract]
public class ServicesAdvancedSearchFilterData : AdvancedSearchFilterData
{
// ....
[DataMember]
public string MeterNumber { get; set; }
// ....
}
When I try to map values like this, it works:
Mapper.Configuration.RecognizePrefixes("Service");
Mapper.CreateMap<AdvancedSearchFilterDataModel, ServicesAdvancedSearchFilterData>();
ServicesAdvancedSearchFilterData servciesFilterData =
Mapper.Map<ServicesAdvancedSearchFilterData>(model);
But I only want "Service" to be recognized as a prefix for certain mappings, since it's also used as a normal part of property names in other mappings. I tried to handle this with a profile, but this didn't work -- no data was mapped:
Mapper.CreateProfile("ServicePrefix").RecognizePrefixes("Service");
Mapper.CreateMap<AdvancedSearchFilterDataModel, ServicesAdvancedSearchFilterData>()
.WithProfile("ServicePrefix");
ServicesAdvancedSearchFilterData servciesFilterData =
Mapper.Map<ServicesAdvancedSearchFilterData>(model);
How can I make it recognize the prefix only when I want it to, either using profiles or some other technique? (I also have other prefixes that I'm going to need it to recognize for other mappings in the same way.)
I achieved this functionality by creating following structure:
I have Person model for my view which is flattened from PersonCombined
public class PersonCombined
{
public Person Person { get; set; }
public Address DefaultAddress { get; set; }
public Contact EmailContact { get; set; }
public Contact PhoneContact { get; set; }
public Contact WebsiteContact { get; set; }
}
public class Person : IWebServiceModel
{
public int ID { get; set; }
public string PersonFirstName { get; set; }
public string PersonSurname { get; set; }
public string PersonDescription { get; set; }
public Nullable<bool> PersonIsActive { get; set; }
}
Then I have separate class for this mapping only that looks like this:
public class PersonCustomMapping : ICustomMapping
{
const string separator = " ";
private static IMappingEngine _MappingEngine;
public IMappingEngine MappingEngine
{
get
{
if (_MappingEngine == null)
{
var configuration = new ConfigurationStore(new TypeMapFactory(), AutoMapper.Mappers.MapperRegistry.Mappers);
configuration.RecognizePrefixes("Person");
configuration.RecognizeDestinationPrefixes("Person");
configuration.CreateMap<Person, MCIACRM.Model.Combine.PersonCombined>();
configuration.CreateMap<MCIACRM.Model.Combine.PersonCombined, Person>();
_MappingEngine = new MappingEngine(configuration);
}
return _MappingEngine;
}
}
}
In my generic view I have mappingEngine property like this:
private IMappingEngine mappingEngine
{
get
{
if (_mappingEngine == null)
{
_mappingEngine = AutoMapper.Mapper.Engine;
}
return _mappingEngine;
}
}
Finally in my generic view constructor i have:
public GenericEntityController(IGenericLogic<S> logic, ICustomMapping customMapping)
: base()
{
this._mappingEngine = customMapping.MappingEngine;
this.logic = logic;
}
And that's how I do mapping:
result = items.Project(mappingEngine).To<R>();
or
logic.Update(mappingEngine.Map<S>(wsItem));
Because I use 1 entity per view I can define custom mapping configuration per entity.
Hope this helps

Categories

Resources