Name of a property as input to attribute constructor - c#

I have a custom attribute and I would like it to have the name of a property as input. Because the name is a string it is a valid input type (as attributes are quite limited as to what they can have as input to their constructors).
But how can I accomplish this?
Take this example code:
public class MyCustomAttribute : Attribute {
public MyCustomAttribute(string propertyName) {}
}
public class Foo {
public bool MyCustomProperty { get; set; }
[MyCustom(SomeMagicAppliedToMyCustomProperty)] // I want the attribute to receive something along the lines of "Foo.MyCustomProperty"
public void Bar();
}
How can I accomplish this with the limitations to what an attribute can receive in its constructor?

There's a new feature in c#-6.0 nameof() that gives the name of the particular property, variable, class etc as a string,
http://www.c-sharpcorner.com/UploadFile/7ca517/the-new-feature-of-C-Sharp-6-0-nameof-operator/
https://msdn.microsoft.com/en-us/magazine/dn802602.aspx

This is not possible.
The attributes can accept only constants, just put your MyCustomProperty name in quotes into the Attribute.

You can also use CallerMemberNameAttribute
https://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute.aspx
public CustomAttribute([CallerMemberName] string propertyName = null)
{
// ...
}

I've used this in an MVC5 application with C#6
private const string jobScheduleBindingAllowed = nameof(JobSchedule.JobId) + ", " + nameof(JobSchedule.Time) + ", " + nameof(JobSchedule.EndTime) + ", " + nameof(JobSchedule.TimeZoneId);
Then when I want to specify the bindings that are valid for the model:
[HttpPost]
public ActionResult CreateJobSchedule([Bind(Include = jobScheduleBindingAllowed)]JobSchedule jobSchedule)
{
// stuff
}
Slightly cumbersome but better than having magic strings everywhere and is type safe so that errors due to renames can be caught at compile time.

Related

Getting the name of a parameter object

I regularly have to export various List<> from within my code to external files. In order to do it in a generic way I wanted to write a function that just takes the name of my variable and then exports according to the fields in that class.
I have that working fine, the only thing what I can't seem to figure out is the name of the variable that I want to export. I can get the type of the class, but that's not what I need. I can get the name of the variable I put it into but that's not what I need either.
Below you'll find the code I'm using:
public class testClass
{
public string firstName {get; set;}
public string lastName {get; set;}
}
private void test()
{
testClass nameOfMyTestClass = new testClass();
// DATA ADDED TO nameOfMyTestClass
...
exportClass(nameOfMyTestClass);
}
public void exportClass(object selectedClass)
{
string objectName = selectedClass.name;
string output = string.Empty;
// GET THE DATA FROM THE SETTINGS
PropertyInfo[] properties = selectedClass.GetType().GetProperties();
foreach (var p in properties)
{
output += "[" + p.Name + "] " + p.GetValue(selectedClass) + Environment.NewLine;
}
// WRITE THE FILE
File.WriteAllText(basePath + #"DATA\" + objectName + ".txt", output, Encoding.UTF8);
}
So I'm passing the variable nameOfMyTestClass as an object into the method exportClass because I want to be able to use this for multiple different classes.
Inside that method I would like to use the name of the variable that I have added as the name of my file: e.g. nameOfMyTestClass.txt
I can get the Class itself by using the GetType() or I can use ToString() but that gives me NAMESPACE.Form1+testClass as a result but I can't find a way to get the actual name of the variable.
Does anybody have an idea how I can accomplish this?
Thanks
You can't get variable names through reflection since they are not present in the compiled assembly's metadata.
But to get the name of the variable, you can use the nameof() operator (introduced with C# 6.0). Note that you would have to add an extra parameter for the name:
exportClass(nameOfMyTestClass, nameof(nameOfMyTestClass));
public void exportClass(object selectedClass, string name)
{ /* ... */ }
The advantage of the nameof operator is, that if you use refactoring (renaming), the passed name will be changed as well, compared to just passing the name in a string literal.
This is not possible because variables don't haves names after they are compiled to IL. But there is a Workaround for you:
void ExportClass(object obj, string className)
{
...
}
var testClass = new TestClass();
ExportClass(testClass, nameof(testClass));
You pass the variable name with nameof to the method and you can use it there.

Get property name C#

I have a class :
class Sample
{
...
}
and define a property like this:
Sample sampleParam =new Sample(...);
and have a function :
private void Func(Sample s)
{}
and use it like:
Func(sampleParam);
can I get the 's' name in the function? I mean can I get "sampleParam"(the name of param)?
It sounds odd; but I need the name of the passed param.
and sorry for this type of asking; I just wanted to ask my question as simple as possible
public string GetParamName(System.Reflection.MethodInfo method,int index)
{
string strParameterName = string.Empty;
if (method != null && method.GetParameters().Length > index)
strParameterName = method.GetParameters()[index].Name;
return retVal;
}
Yes there is a way to achieve this through Reflection...
You should never reference variable or property names from called methods - it's bad manners and bad design (mostly the latter).
There is nameof operator in C# 6.0, but it wasn't designed for this.
You could use expression trees, which would slightly change your syntax. If sampleParam is not a property but a variable, you can't really access it, because compiler does not store any references to that name in generated dll file.
This isn't exactly what you're asking for, but is perhaps closer to what you want, but you could take a look at System.Environment.StackTrace.
I think it is not possible to get the name for a variable which value is passed to a method. But there is the compiler service CallerMemberNameAttribute which copies the name of the caller method (here the get accessor of our property Name) to the calling method if not specified:
class Person {
static void Main(string[] args) {
Person bart = new Person();
bart.Name = "Bart";
Console.ReadKey();
}
private string _name;
public string Name {
get {
return _name;
} set {
_name = value;
PropertyChanged(); //no need to fill in `Name` here! :)
}
}
//automatically copy caller's name to `propertyName`, at compile time
private void PropertyChanged([CallerMemberName] string propertyName = "") {
object propertyValue = this.GetType().GetProperty(propertyName).GetValue(this);
Console.WriteLine("Property '" + propertyName + "' changed the value to '" + propertyValue + "'");
}
}
Prints:
Property 'Name' changed the value to 'Bart'
If you mean can you get the name 'sampleParam' from INSIDE func? The the answer is no. There is nameof() in C#6.0 but 'sampleParam' inside not in scope inside the func. The variable s (of type Sample) is crated and assigned a ref to sampleParam.
You can get the name "s" inside Func.
You can get the name "sampleParam" in the calling class (outside Func).
Example (available on dotnetfiddle)
using System;
public class Program
{
public static Sample sampleParam {get; set;} =new Sample();
public static void Main()
{
Console.WriteLine($"Name of property: {nameof(sampleParam)}");
Func(sampleParam);
}
private static void Func(Sample s)
{
Console.Write($"Name of parameter: {nameof(s)}");
}
}
public class Sample
{
}
Output:
Name of property: sampleParam
Name of parameter: s
Now this is a rather simplistic example. Func exists in the same class as sampleParam and there is only one property so one could derive the name but my assumption is despite your question stating it this way you are looking for a more generalized solution. The problem is that inside func the calling parameter name is not in scope. You could capture it via nameof in the calling method and pass it into func but you shouldn't that would be horrible code for a variety of reasons.
As described what you are doing is intentionally building fragile tightly coupled code which is something developers work very hard to prevent. The caller is not going to know the name of the parameter passed into func is important and shouldn't. This leads me to believe this an xy problem.

How to handle nameof(this) to report class name

I'd like to use the following C#6 code
var joe = new Self();
Console.WriteLine(joe);
... and get the following output:
joe
The following attempt
class Self {
public string Name { get; set; } = nameof(this);
public override string ToString() {
return Name;
}
}
fails as nameof cannot be applied to this. Is it there a workaround for this problem?
EDIT. The scenario I'm working with assures that no two references point to the same Self object.
No, nameof is designed to refer to the compile-time name of the member you're referring to. If you want an object to have a Name property as part of its state, that is independent of how you get to the Name property - as Frédéric Hamidi says, there could be multiple variables (or none) referring to the same object. Basically you need to differentiate between an object and a variable which happens to refer to that object.
However, if you have a constructor to specify the name, you could then use a couple of tricks to make it easier to get the right name:
class Self
{
public string Name { get; }
public Self([CallerMemberName] string name = null)
{
this.Name = name;
}
}
Then:
class Foo
{
private Self me = new Self(); // Equivalent to new Self("me")
public void SomeMethod()
{
// Can't use the default here, as it would be "SomeMethod".
// But we can use nameof...
var joe = new Self(nameof(joe));
}
}
Maybe you can use the following method:
class Self
{
public override string ToString()
{
return this.GetType().Name;
}
}
You can simply use nameof on the variable itself:
Console.WriteLine(nameof(joe));
Here's a working example using the current Roslyn version
The idea for nameof is to make things type safe for specifying program elements during runtime but with compile time type safety checking.
One should atomize what one wants to display. For example in my error messages I include the pertinent information of the class name and the method as such and its checked, so if I change any of the names they are caught as a compile time error:
class Operation
{
public void Execute()
{
try { ... }
catch (Exception ex)
{
Console.Writeline($"{nameof(Operation)}.{nameof(Execute)} has encountered exception:{Environment.NewLine}{Environment.NewLine}{ex.Message}" );
}
}
}
Output
Operation.Excecute has exception:
...
With that said you should override ToString() and report the class name as such
public override string ToString() { return nameof(Self); }
I usually create an internal constant for it when dealing with long class names:
private const string SomeConst = nameof(Self);
Then you can use that in your code:
Console.WriteLine(SomeConst);

custom attribute for string property

i have a question.
I would like to do something like that:
[PutStars]
public string telephone
where PutStars could be a custom attribute for example.
PutStars acts on the string, so it replace telephone value [333-123456789] and when getting value, it retrieves for example [333-12xxxx789].
Is it possible?
Thanks a lot!
Well, you can implement a helper method and call it when getting the value:
private string _tel;
public string Tel
{
set{ _tel = value; }
get {
return _tel.PutStars();
}
}
public static string PutStars(this string str)
{
return str.Replace("1", "*");
}
Alternatively when you get the string you can do:
var starred = myObj.Tel.PutStars();
The closest you'll get to that inbuilt will probably be [PasswordPropertyText], but a: that is intended to mask an entire field, and b: it depends entirely on the UI framework you are using looking for this attribute; nothing is automatic in attributes. Your best bet, frankly, is probably to add a second property that you use for UI binding:
public string Telephone {get;set;}
public string TelephoneMasked {
get { /* your code here */ }
}
and bind to TelephoneMasked.

How to make a property required in c#?

I have requirement in a custom class where I want to make one of my properties required.
How can I make the following property required?
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
If you mean "the user must specify a value", then force it via the constructor:
public YourType(string documentType) {
DocumentType = documentType; // TODO validation; can it be null? blank?
}
public string DocumentType {get;private set;}
Now you can't create an instance without specifying the document type, and it can't be removed after that time. You could also allow the set but validate:
public YourType(string documentType) {
DocumentType = documentType;
}
private string documentType;
public string DocumentType {
get { return documentType; }
set {
// TODO: validate
documentType = value;
}
}
.NET 7 or newer
Syntax
public class MyClass
{
public required string Name { get; init; }
}
new MyClass(); // illegal
new MyClass { Name = "Me" }; // works fine
Remarks
The required properties must declare a setter (either init or set).
Access modifiers on properties or setters cannot be less visible than their containing type, as they would make impossible to initialize the class in some cases.
public class MyClass
{
internal required string Name { get; set; } // illegal
}
Documentation
Official documentation here
Feature demo here
.NET 6 or older
See this answer
If you mean you want it always to have been given a value by the client code, then your best bet is to require it as a parameter in the constructor:
class SomeClass
{
private string _documentType;
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
public SomeClass(string documentType)
{
DocumentType = documentType;
}
}
You can do your validation – if you need it – either in the property's set accessor body or in the constructor.
With the release of .NET 7 and C# 11 in November 2022 you can now use the required modifier this way:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName) => FirstName = firstName;
public required string FirstName { get; init; }
public int Age { get; set; }
}
And when you don't have the required properties it will throw an error when you try to initialize an object.
For more information refer to:
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#required-members
https://learn.microsoft.com/en-us/dotnet/csharp/properties#init-only
Add a required attribute to the property
Required(ErrorMessage = "DocumentTypeis required.")]
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
For custom attribute detail Click Here
I used an other solution, not exactly what you want, but worked for me fine because I declare the object first and based on specific situation I have different values. I didnt want to use the constructor because I then had to use dummy data.
My solution was to create Private Sets on the class (public get) and you can only set the values on the object by methods. For example:
public void SetObject(string mandatory, string mandatory2, string optional = "", string optional2 = "")
This one liner works in C# 9:
public record Document(string DocumentType);
new Document(); // compiler error
new Document("csv"); // correct way to construct with required parameter
This explains how it works. In the above code, Document is the name of the class or "record". That first line of code actually defines an entire class. In addition to this solution essentially making a required DocumentType property (required by an auto implemented constructor), because it uses records, there are additional implications. So this may not always be an appropriate solution, and the C# 11 required keyword will still come in handy at times. Just using record types doesn't automatically make properties required. The above code is a special syntax way of using records that essentially has this effect as well as making the property init only and causes a deconstructor to be automatically implemented.
A better example would be using an int property instead of a string since a string could still be empty. Unfortunately I don't know of any good way to do extra validation within the record to make sure the string is not empty or an int is in range, etc. You would have to go deeper down the TOP (type driven development) rabbit hole, which may not be a bad thing. You could create your own type that doesn't allow empty strings or integers outside your accepted range. Unfortunately such an approach would lead to runtime discovery of invalid input instead of compile time. There might be a better way using static analysis and metadata, but I've been away from C# for too long to know anything about that.

Categories

Resources