Enforce properties of an object not beeing null - c#

My business logic receives often objects (DTOs) like the following one:
public class CreateUserRequest
{
public string FirstName { get; set; }
public string LastName { get; set; }
public EMailAddress EMail { get; set; }
}
This is simplified and I could use this class to create a new user in my app.
However, many times some of the properties have to be set (!= null), so I need to enforce them like for example like this:
public class CreateUserRequest
{
CreateUserRequest()
{
ThrowIfAnyNotValid();
}
public string FirstName { get; set; }
public string LastName { get; set; }
public EMailAddress EMail { get; set; }
public void ThrowIfAnyNotValid()
{
Ensure.ThrowIfNull(FirstName, nameof(FirstName));
Ensure.ThrowIfNull(LastName, nameof(LastName));
Ensure.ThrowIfNull(EMail, nameof(EMail));
}
}
This works nice, but I am wondering if there is an easier solution.
I know that there is the nullable context feature like described here, but this is not exactly what I want.
If I enable this feature, the compiler will throw warnings and complains that all fields of my class could be null.
The only way to avoid this is to list all of them in the constructor, but this is again much boilerplate code if my classes have many properties.
Actually I need a class where some properties are enforced to be not null by the compiler.
Something like this:
public class CreateUserRequest
{
public stringForcedNotNull FirstName { get; set; }
public stringForcedNotNull LastName { get; set; }
public stringForcedNotNull EMail { get; set; }
}
So this would throw an exception or even a compiler error:
var request = new CreateUserRequest();
And only this would be fine:
var request = new CreateUserRequest()
{
FirstName = "Joe",
LastName = "Schmidt",
EMail = "Joe.Schmidt#foe.de"
}
Is there a way in C# that I missed?

There are many ways you can ensure that there won't be any null values on construction. However there is probably no simple way to enforce not null values automatically during whole lifetime of instance of your classes as it would be way too processing power hungry with little gain. Common appoach would be to check values every time you need them, or only on creation.
You can add mandatory parameters to constructor like this:
public class CreateUserRequest
{
CreateUserRequest(string FirstName, string LastName, EMailAddress EMail)
{
this.FirstName = FirstName;
this.LastName = LastName;
this.EMail = EMail;
}
public string FirstName { get; set; }
public string LastName { get; set; }
public EMailAddress EMail { get; set; }
}
This code won't allow you to call new CreateUserRequest() without parameters and thus create empty values.
Another solution I came up with is to check values dynamically. I made two separated classes so you don't have to put chcek code into each one, you just inherit from BaseClass when creating new clases
public class CreateUserRequest : BaseClass
{
public string FirstName { get; set; }
public string LastName { get; set; }
public EMailAddress EMail { get; set; }
}
public class BaseClass
{
public BaseClass()
{
if (!this.IsValid)
throw new Exception(/*custom message or whatever*/);
}
public bool IsValid
{
get
{
if (this.GetType().GetProperties().Any(p => p.GetValue(this) == null))
return false;
else
return true;
}
}
}
You can also call IsValid property from anywhere which might be handy and you might even move it out of constructor.
Last thing I'd like to mention is default value.
public class CreateUserRequest
{
public string FirstName { get; set; } = "John";
[DefaultValue("Doe")]
public string LastName { get; set; }
[DefaultValue("John.Doe#email.com")]
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
public EMailAddress EMail { get; set; }
}
Note that there are many options to do that.
First is the simplest one.
Second utilizes DefaultValueAttribute which can be handy in combination with other features but practically does the same thing as first one.
Last one is example of using JsonProperties coming from NewtonsoftJson. When you have for example web application and rely on data comming from Ajax requests, this can come really handy.
Another thing reason why this approach is really helpful is because many methods especially from Linq library can work with default values like FirstOrDefalt() which would in your case return null but in my case it would return values stored in DefaultValueAttribute.

Related

How to automatically create a default constructor which sets default values

Is there any way to auto generate a constructor which looks like this:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public User(int id, string name)
{
Id = 0;
Name = "";
}
}
Currently I am creating a constructor like that with the refactoring tool (CTRL + .):
public User(int id, string name)
{
Id = id;
Name = name;
}
and editing each line afterwards which is pretty cumbersome when you have 20 properties per class. Is there a better way to that?
(Maybe to define a code snippet, so that we can somehow read the class properties with reflection and define them as snippet parameters?)
If you have a class with 20 properties, why do you need a constructor with 20 parameters? Maybe have a sense, but I usually create constructors to initialize properties that are relevant, to simplify the code, not to set all properties.
For your class, you can set the default values when you define the property and all constructors will use this values as the default.
public class User
{
public int Id { get; set; } = 0;
public string Name { get; set; } = string.Empty;
// Here you can even omit the constructor
public User()
{
}
}
Another thing that maybe useful is define a constructor with X parameters and reuse this constructor in other constructors with less parameters:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public User()
: this(0, string.Empty)
{
}
public User(int id, string name)
{
Id = id;
Name = name;
}
}
You can replace this(0, string.Empty) for this(default, default) if you want use the default value of each type.
If you need object create with default value for properties. You can code like this:
public class User
{
public int Id { get; set; } = 0;
public string Name { get; set; } = "";
}
Purpose of quick action "generate constructor" make method contructor for assign value to fields or properties. Don't use it in the case of just assigning default values.
do you mean initialize properties? Initializing properties through the code reflection mechanism also requires one-by-one assignments. For private object properties, it is necessary to de-private encapsulation. The operation of initializing properties in c# is generally to initialize object properties or object initializers in the form of constructors. Thank you hope it helps you
class Program
{
static void Main(string[] args)
{
Student student = new Student()
{
age = 25,
name = "java",
sex = "female"
};
}
class Student
{
public int age { get; set; }
public string name { get; set; }
public string sex { get; set; }
public Student()
{
}
public Student(int age, string name,string sex)
{
this.age = age;
this.name = name;
this.sex = sex;
}
}
}

Send a limited/reduced class to frontend

What I want
I want to send a limited/reduced class/object to frontend (as JSON). I use .NET Core 5.
What I have
I have a model class like this:
namespace Tasks.Models
{
public class Resources
{
public Guid Id { get; set; }
public string Type { get; set; }
public string Url { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public DateTime? Createdon { get; set; }
public Guid Userid { get; set; }
public Guid Taskid { get; set; }
public int Clicked { get; set; }
public byte Active { get; set; }
+++ many more properties
}
}
Now depending on the which controller that calls this model I want to have different "kind" of models. So if the resource is file I maybe want the properties Id,Type,Name. But if the resource is URL I want Id, Url, Name.
I tried setting up a method that "initialized the fields I wanted, but that also returned all properties
public static Responses FileResponse()
{
var response = new Responses()
{
Id = new Guid(),
Name = "",
Type = "File",
};
return response;
}
Now, when I call the Resources class or this method I get all properties, and returning it to the view presents all properties, but mostly as null, because I only set the three fields in the method.
What is the recommended way of solving this?
If you want to remove the field if it's null instead of showing in json with null value.
public class Resources
{
public Guid Id { get; set; }
public string Type { get; set; }
// if null, dont show it in JSON output
[JsonIgnoreAttribute(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Url { get; set; }
// if null, dont show it in JSON output
[JsonIgnoreAttribute(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Name { get; set; }
public string Description { get; set; }
public DateTime? Createdon { get; set; }
public Guid Userid { get; set; }
public Guid Taskid { get; set; }
public int Clicked { get; set; }
public byte Active { get; set; }
}
PS: Fiddle https://dotnetfiddle.net/hiMAci
It is just limiting the Resource class I am not able to do
Yep, side effect of C# being strongly typed, with object X definitely having properties Y and Z. You need differently shaped objects - either full on classes or records - that name the reduced set of properties because the serializer is going to look a tthe object and ser every property it can find.
You could make a new class for every variation - quick and easy with records, and easy to pass around inside your C#:
public record FileThing(string Id, string Type, string Name);
//make a new one and return it
new FileThing(someResources.Id, someResources.Type, someResources.Name);
Or can consider using an anonymous type if you're literally looking to put a few properties into some json, down a socket to a consuming front end (I can't quite decide what you mean by "view" - it doesn't seem to be an MVC View) that only cares about a few props out of many
So if the resource is file I maybe want the properties Id,Type,Name. But if the resource is URL I want Id, Url, Name.
public ActionResult SomeControllerMethod(){
if(isFile)
return Ok(new { someResources.Id, someResources.Type, someResources.Name });
else if(isUrl)
return Ok(new { someResources.Id, someResources.Url, someResources.Name });
}
Anonymous types are a bit harder to work with because the compiler writes the class for you, so it's tricky to do things like declare return types from methods if the method is returning an AT.. But if you're using it as some fill-in all within one method, such as a "make this and serialize it", they work well..
I think your approach is not the right one here. I tend to follow more general OO guidelines in this situation (note, some consider these a bit dated, and other solutions exist. But they are still commonly used)
You write against an interface. So let's see what you want... A guid, type and name. All other deatils aren't important.
public interface IResourceDetails
{
public Guid Id { get; }
public string Name { get; }
public string Type { get; }
}
And you can have multiple of these interfaces.
You could then implement the interfaces per type. But I would probably combine them in a base class
public abstract class ResourceBase : IResourceDetails
{
public Guid Id { get; } = new ();
public string Name { get; init; }
public string Type { get; }
public ResourceBase(string type)
{
Type = type;
}
}
Each resource type would have it's own implementation
public class FileResource : ResourceBase
{
public FileResource() : base("File") { }
// File-specific properties.
public string Description { get; init; }
public DateTime? Createdon { get; init; }
}
The response method then could be made generic and look like this
public static IActionResult Response(IResourceDetails resource)
{
return Ok(new
{
resource.Id,
resource.Name,
resource.Type,
});
}

Best approach to hold different classes as a property

I probably don't know the correct terminology to look this up on google so I'm asking here.
Say I want to have a front end control to run different SQL queries in Winforms that allow entering the parameters which will be generated at runtime.
public class AnalysisQuery
{
public string QueryName { get; set; }
public string QueryDescription { get; set; }
public string QuerySQL { get; set; }
public T QueryParameters { get; set; } // <-- Not sure how to do this
}
and say I have 2 entirely different classes that hold the parameters for a particular query
public class EmployeeQueryParameters
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Occupation { get; set; }
public DateTime StartingDate { get; set; }
public bool IsMarried { get; set; }
}
public class CarQueryParameters
{
public string CarName { get; set; }
public string CarModel { get; set; }
public string CarMaker { get; set; }
public bool IsDiesel { get; set; }
}
How do I hold these different classes in the property QueryParameters?
What is the best way to do this?
Ultimately I need to use either EmployeeQueryParameters or CarQueryParameters for a datasource, eg
someControl.DataSource = new EmployeeQueryParameters()
{
FirstName = "",
LastName = "",
Occupation = "",
StartingDate = new DateTime(2018, 10, 18),
IsMarried = true
};
What I have tried so far....
1)I've looked into interfaces but this looks like it will only work if all properties are the same in each EmployeeQueryParameters and CarQueryParameters class.
2) This link shows an example to hold different types as list of parameters. It kind of works but ultimately the type must still be known at the end to retrieve the correct type, eg
public class AnalysisQuery
{
public string QueryName { get; set; }
public string QueryDescription { get; set; }
public string QuerySQL { get; set; }
public Parameter QueryParameters { get; set; }
public AnalysisQuery()
{
QueryName = "QueryName1";
QueryDescription = "QueryDescription1";
QuerySQL = "QuerySQL1";
QueryParameters = Parameter.Create<EmployeeQueryParameters>(
new EmployeeQueryParameters() { FirstName = "first name" });
}
}
still requires the type to be known to get the value so kind of defeats the object of using a generic parameter?
var analysisQuery = new AnalysisQuery();
EmployeeQueryParameters parameters =
analysisQuery.QueryParameters.Get<EmployeeQueryParameters>();
The answer depends a lot on your UI. Do you have a form that uses AnalysisQuery as a model in which you dynamically add new key value pairs to define parameters for the query? Then I recommend using a Dictionary for QueryParameters. Do you use only a limited number of predefined types of queries, then I recommend using AnalysisQuery as your model, which then you switch based on a dropdown or radiobutton list, etc. Even more, if your UI doesn't know (or shouldn't know) the list of predefined types, then you will have to construct the UI based on the actual type and values of the object in QueryParameters, in which case you can just declare it as an object and get the information using reflection.
Bottom line, your question is too vague for a clear answer.

Trying to get data from a seperate class c# using string.format

namespace StudentSearch
{
public class StudentRecord : IEquatable<StudentRecord>
{
public string StudentID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Gender { get; set; }
public string State { get; set; }
public int? Age { get; set; }
public decimal? GPA { get; set; }
public override string ToString()
{
return string.Format("{0,-11}{1,-25}{2,3:d} {3,-7}{4,-11}{5:n2}",
StudentID, (FirstName + " " + LastName), Age, Gender, State, GPA);
}
}
partial class frmStudentSearch
{
HashSet<StudentRecord> hsAllStudents = new HashSet<StudentRecord>(){
new StudentRecord {StudentID = "G00002728", LastName = "Bryant", FirstName = "Tim", Gender = "M", State = "UT", Age = 47, GPA = 3.98M},
-sic-
};
}
That piece of code is stored in ModNames.cs under the StudentSearch namespace, in public class StudentRecord
I'm trying to make a call from public partial class StudentSearch : Form, to StudentRecord to take this data, check it's validity, then display it in a DataDisplayGrid.
Thing is, I haven't really dealt with multiple classes, or class to other classes in c# or generally programming much before and this is kind of throwing me for a loop.
I tried to just make a call using variations on
StudentRecord.ToString();
I haven't really messed with string.format before either, so doing it between classes is throwing me for a loop, both on the syntax to correctly call this method, and how to type/hold the data.
The information has to be out there on the 'net somewhere, but I just can't find the right search terms on stackoverflow or google to turn up an answer as to how I do this.
I've checked msdn, but if I've come across the answer, I didn't realize it.
You need to create an instance of your class to access its properties and methods.
StudentRecord student = new StudentRecord();
student.ToString();

Accessing Class and Property name inside an Attribute

Is there any way to access the Class and Property name which you attached an attribute to inside the attribute?
For example
public class User {
public string Email { get; set; }
public string FirstName { get; set; }
[MyAttribute]
public string LastName { get; set; }
}
And then in the MyAttribute class
public class MyAttributeAttribute {
public MyAttributeAttribute () : base() {
string className = /*GET CLASS NAME - should return "User" */
string propertyName = /*GET PROPERTY NAME - should return LastName*/
}
}
I know I can pass in the information in the constructor, but hoping there is an easy way somehow to save on retyping info over and over again either via reflection or...
Sorry, but no that's not possible. You could also have
public class User {
public string Email { get; set; }
public string FirstName { get; set; }
[MyAttrubute]
public string LastName { get; set; }
}
[MyAttrubute]
public class OtherClass {
[MyAttrubute]
public string AnotherProperty { get; set; }
}
The attribute can be created from anywhere. Even the following is a valid way to create an instance:
var att = new MyAttribute();
Your question could be boiled down to "Can I detect where my custom class is instantiated from?". In my last example, StackTrace could probably be used. But with attributes they are being constructed by the .NET runtime, so you would not be able to go that route.

Categories