I have a class with some properties with DisplayNameEx attribute, which is derived from DisplayNameAttibute:
public class Settings
{
[DisplayNameEx("User")]
public UserData User { get; set; }
}
public class DisplayNameExAttribute : DisplayNameAttribute
{
public DisplayNameExAttribute(string id)
{
}
}
I pass as string id ALLWAYS name of my property, so it would be easier writing code this way:
public class Settings
{
[DisplayNameEx()]
public UserData User { get; set; }
}
Property name I can get here with CallerMemberName attribute:
public class DisplayNameExAttribute : DisplayNameAttribute
{
public DisplayNameExAttribute([CallerMemberName] string propertyName = null)
{
//propertyName I get, what about class name (Settings in my case)?
}
}
Is it possible to get class name also?
It's impossible. Best way in your case is parameter with class name in the constructor of the attribute:
public class DisplayNameExAttribute : DisplayNameAttribute
{
public DisplayNameExAttribute(string className = null)
{
}
}
and then use it like this:
public class Settings
{
[DisplayNameEx("Settings")]
public UserData User { get; set; }
}
I used a similar technique before .NET 4's localizable DisplayAttribute. From .NET 4 I use the DisplayAttribute because it supports localization and it's much more powerful.
I personally would not recommend your idea because of mainly two reasons.
Potential refactoring issues. If one renames your property, he doesn't have any idea that he should also rename the resource with the same name. Same stands for class names. After a few months even you can forget it time to time.
The code is not straightforward. Other developers could not easily understand what your attributes are doing, and even hard to see at first glance that it's related to localization.
I think the best is just to put there those strings.
Related
I've got 2 classes with many different properties and one similar property:
public class A
{
// Lots of specific properties
[Display(Name="Dun and bradstreet number")]
public string DunAndBradstreetNumber {get;set;}
}
public class B
{
// Lots of specific properties
[Display(Name="Dun and bradstreet number")]
public string DunAndBradstreetNumber {get;set;}
}
I realise I have an abundance of choice and I just want to make sure i'm choosing the most semantically correct and popular choice.
1:-----------
Should I declare another class:
public class DunAndBradstreetNumber
{
[Display(Name="Dun and bradstreet number")]
public string DunAndBradstreetNumber {get;set;}
}
and then make class A and B have pointers inside them eg.?
public class A
{
public DunAndBradstreetNumber DunAndBradstreetNumber { get; set; }
}
or
2:-----------
inherit from the DunAndBradstreetNumber?
public class A : DunAndBradstreetNumber
{
//...
}
3:-----------
declare a global function and put that in the get method of each DunAndBradstreetNumber?
public class A
{
public string DunAndBradstreetNumber {
get
{
// Run some function that I may need help on to apply property validation via attributes to
}
set;
}
}
Any more better choices?
My class A and B are domain models using entityframework if that helps at all.
The problem i'm trying to solve is to not have to declare the validation and display attributes twice in different models.
P.S - your opinion is fine... I just want to know the eventualities of the choice I have to make here (albeit its relative insignificance).
I have been looking into DataAnnotations and creating my own DataAnnotations for future use - mainly in MVC4 (which is fairly easy it's safe to say). I want to verify how useful, effective and easy to use they will be if I use the same Model classes in a WPF project.
public class Customer
{
public int Id { get; set; }
[Required()]
public string Name { get; set; }
}
public class ViewModelBase : IDataErrorInfo, INotifyPropertyChanged
{
//... (INotifyPropertyChanged)
public string Error
{
get
{
return string.Empty;
}
}
public string this[string columnName]
{
get
{
//According to tutorials, something here
return string.Empty;
}
}
}
So if I were to move on to creating a CustomerViewModel which inherits from the base class, would I have to present a subset view of the model properties like:
public class CustomerViewModel : ViewModelBase
{
[Required]
public string Name { get; set; }
}
Meaning I have to implement the annotations again, or is it possible to just use the model and somehow reflect model validation back to the front end using WPF's MAGICAL binding?
I have been looking at numerous articles, but none of which seem to be neat or very consice - such as:
http://blog.paulbetts.org/index.php/2010/04/27/wpf-data-validation-using-dataannotations/
Why would you put another Name property in your viemodel?
If you have a Customer property in your viewmodel, you can access it in you xaml like:
{Binding Customer.Name}
This will automatically take your dataanotations from your model class.
Edit: For a good example see: http://www.codeproject.com/Articles/98681/Validating-User-Input-WPF-MVVM
I have many classes that have the following members/methods:
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public bool isNamed(String name) { return getName().Equals(name); }
Every time I create a new class that has a member "name", I have to rewrite all these.
Is there a way to write the methods one time and to make them apply to any class I want?
Your code can be converted to:
public String Name { get;set;}
Then you can use it as so:
nObject.Name = "Stefan";
if(nObject.Name == "Stefan"){
// do something
}else{
// do something else
}
To apply to all the classes automatically you can just make this into an interface:
public interface INameable{
public String Name {get;set;}
}
Doing this will allow you to inherit from other base classes of importance.
see here for an example
class YourClass : INameable{
//implementation
}
And now, YourClass has "Name" property automatically inserted.
You'd simply define a base class (you could make it abstract):
public abstract class Named
{
public string Name { get; set; }
}
and inherit from it:
public class Person : Named
{
}
You don't really need isNamed as in C#, it is perfectly safe to compare strings with ==.
If your class already inherits from another class which is not Named, you'll have to manually add the Name auto property or resort to simulated multiple inheritance.
Alternatively, you could create a specific modification of Named for every base class:
public abstract class NamedLifeForm : LifeForm
{
public string Name { get; set; }
}
public class Person : NamedLifeForm
{
// Person inherits both a Name and all relevant members of LifeForm
}
Another alternative would be to create a generic wrapper, Named<T>, that would have two properties: the Name and an instance of T. But that would make construction and access cumbersome, so I don't recommend it.
C# has AutoProperties just for that:
public String Name {get; set; }
This handles both the getName() and the setName() you talked about.
Usage:
To set a value: Name = "MyName;
To get a value: string theName = Name;
I'd suggest reading up on Object Oriented Programming. You can save yourself a lot of time and effort (and heckling). Here is a good primer http://www.amazon.com/Beginning-Object-Oriented-Programming-Dan-Clark/dp/1430235306
To answer your specific question, you should read about inheritance. It lets you define a "Parent" class with functions. Then you can inherit with "Child" classes and have those same functions.
http://msdn.microsoft.com/en-us/library/ms173149(v=vs.80).aspx
Here is a code example
public class PersonBase
{
private String name;
public String getName()
{
return this.name;
}
public void setName(string name)
{
this.name = name;
}
public bool isNamed(string name)
{
return this.name.Equals(name);
}
}
public class Employee : PersonBase
{
}
Employee will now have whatever was defined by PersonBase.
As others have pointed out, you can simplify you code with properties. Also you should check for null values before using "this.name".
Here is a link to what properties are:
http://msdn.microsoft.com/en-us/library/x9fsa0sw(v=vs.80).aspx
The simplified code example would be:
public class PersonBase
{
public String Name { get; set; }
}
public class Employee : PersonBase
{
}
I hope this helps get you pointed in the right direction for learning about these concepts.
I have a lot of similar classes generated by svcutil from some external WSDL file. Any class has a Header property and string property which named class name + "1".
For instance, I have classes: SimpleRequest that has Header property and SimpleRequest1 property.
Another one is ComplexRequest that has Header property and ComplexRequest1 property.
So, I want to create a common interface for such classes. So, basically I can define something like that:
interface ISomeRequestClass {
string Header;
// here is some definition for `class name + "1"` properties...
}
Is it possible to define such member in interface?
Here is post edit goes...
Here is sample of generated class:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(IsWrapped=false)]
public partial class SimpleRequest
{
public string Header;
[System.ServiceModel.MessageBodyMemberAttribute(Name="SimpleRequest", Namespace="data", Order=0)]
public SimpleRequestMsg SimpleRequest1;
public SimpleRequest()
{
}
public SimpleRequest(string Header, SimpleRequestMsg SimpleRequest1)
{
this.Header = Header;
this.SimpleRequest1 = SimpleRequest1;
}
}
POST EDIT 2
I changed definition of this annoying +1 property to represent real actual picture. It's all has different class types. So how can I pull it out to common interface?
POST EDIT 3
Here is coupled question that could bring more clarify.
EDIT (after seeing your code sample): Technically speaking, your code does not have a Header property, it has a Header field. This is an important difference, since you cannot specify fields in an interface. However, using the method described below, you can add properties to your classes that return the field values.
Is it possible to define such member in interface?
No, interface names cannot be dynamic. Anyway, such an interface would not be very useful. If you had an instance of class ISomeRequestClass, what name would you use to access that property?
You can, however, use explicit interface implementation:
interface ISomeRequestClass {
string Header { get; set; }
string ClassName1 { get; set; }
}
class SomeClass : ISomeRequestClass {
string Header { ... }
string SomeClass1 { ... }
// new: explicit interface implementation
string ISomeRequestClass.ClassName1 {
get { return SomeClass1; }
set { SomeClass1 = value; }
}
}
You could define your interface more generally:
interface ISomeRequestClass {
string HeaderProp {get; set;}
string Prop {get; set;}
}
And your concrete classes could be extended (in an extra code file) by mapping interface members to class fields like so:
public partial class SimpleRequest : ISomeRequestClass
{
public string HeaderProp
{
get
{
return Header;
}
set
{
Header = value;
}
}
public string Prop
{
get
{
return SimpleRequest1;
}
set
{
SimpleRequest1= value;
}
}
}
Putting aside for a moment the naming of your classes and properties.
If you're looking to create an interface with a property relevant to your specific +1 type, you have a couple of options.
Use a base class for your +1's
If both of your +1 classes inherit from the same base class you can use this in your interface definition:
public interface IFoo
{
[...]
PlusOneBaseType MyPlusOneObject{get;set;}
}
Create a generic property on your interface
This method allows you to specify the type for the +1 property as a generic parameter:
public interface IFoo<TPlusOneType>
{
[...]
TPlusOneType MyPlusOneObject{get;set;}
}
Which you might use like:
public class SimpleRequest : IFoo<SimpleRequest1>
{
[...]
}
Update
Given that your classes are partial classes, you could always create a second (non machine generated) version of the partial class that impliments your interface.
You mentioned svcutil so I assume you are using these classes as WCF DataContracts?
If that is the case then you could make use the name property of DataMemberAttribute.
interface IRequest
{
string Header { get; set; }
string Request1 { get; set; }
}
[DataContract]
class SimpleRequest : IRequest
{
[DataMember]
public string Header { get; set; }
[DataMember(Name="SimpleRequest1"]
public string Request1 { get; set; }
}
[DataContract]
class ComplexRequest : IRequest
{
[DataMember]
public string Header { get; set; }
[DataMember(Name="ComplexRequest1"]
public string Request1 { get; set; }
}
If you are concerned giving yourself more work when you regenerate the code at some point in the future, then I recommend you write a PowerShell script to do this transformation automatically. After all svcutil is just a script written by some guy at Microsoft. It is not magic or "correct" or "standard". Your script can make a call to scvutil and then make a few quick changes to the resulting file.
EDIT (After seeing your edit)
You are already using MessageBodyMemberAttribute's Name property so just change this:
public string SimpleRequest1;
To
public string Request1;
Do you actually need these classes to have a common interface? I'd be tempted to instead create a wrapper interface (or just a concrete class) which could then use reflection to access the fields in question:
// TODO: Make this class implement an appropriate new interface if you want
// to, for mocking purposes.
public sealed class RequestWrapper<TRequest, TMessage>
{
private static readonly FieldInfo headerField;
private static readonly FieldInfo messageField;
static RequestWrapper()
{
// TODO: Validation
headerField = typeof(TRequest).GetField("Header");
messageField = typeof(TRequest).GetField(typeof(TRequest).Name + "1");
}
private readonly TRequest;
public RequestWrapper(TRequest request)
{
this.request = request;
}
public string Header
{
get { return (string) headerField.GetValue(request); }
set { headerField.SetValue(request, value); }
}
public TMessage Message
{
get { return (TMessage) messageField.GetValue(request); }
get { messageField.SetValue(request, value); }
}
}
You could use expression trees to build delegates for this if the reflection proves too slow, but I'd stick to a simple solution to start with.
The advantage of this is that you only need to write this code once - but it does mean creating a wrapper around the real request objects, which the partial class answers don't.
I have an employee class generated by Entity Framework (EF).
public partial class employee
{
private string name;
public string Name
{
get{return name;}
set{ name = value;}
}
}
Now I want to put a required attribute in the name property to use in for MVC3 validation in another employee partial class which is written by me in order to extend the one which is generated by EF so that I don't have to rewrite my code if I refresh the model generated by EF.
My written partial class is in the same assembly and name space.
public partial class employee
{
// What should I write here to add required attribute in the Name property?
}
It is actually possible only through buddy class but it is not recommended way. You should keep your validation in custom view model because often you need different validations for different views but your entity can keep only single set of validation attributes.
Example of buddy class:
using System.ComponentModel.DataAnnotations;
[MetadataType(typeof(EmployeeMetadata))]
public partial class Employee
{
private class EmployeeMetadata
{
[Required]
public object Name; // Type doesn't matter, it is just a marker
}
}
You can't, as far as I'm aware - it's just not feasible.
You should possibly look to see whether MVC3 has any way of adding attributes elsewhere (e.g. to the type) which relate to another property.
Alternatively, you could add a proxying property:
[ValidationAttributesHere]
public string ValidatedName
{
get { return Name; }
set { Name = value; }
}
Another way to do this is:
private class EmployeeMetadata
{
//the type HAS to match what your have in your Employee class
[Required]
public string Name { get; set; }
}
public partial class Employee : EmployeeMetadata
{
}
At least this worked with Linq to SQL. However I had trouble accessing the attributes through GetCustomAttributes (even using System.Attribute.GetCustomAttributes didn't seem to help). Nonetheless MVC did respect those attributes. Additionally this will not work with inheriting from interfaces. Passing attributes from interface will only work using MetadataType class attribute (see answer by Ladislav Mrnka).