How to define initial values according to generic value? - c#

I have a generic entity class.
if T is guid, I want to initialize new guid value .
if T is int, I want to initialize id =0;
if T is string I want to initialize id =string.empty
What is the most suitable way to do this ?
public class BaseEntity<T>{
public string Id { get; set; } ;
public DateTime? CreatedAt { get; set; } = DateTime.Now;
public DateTime? UpdatedAt { get; set; }= DateTime.Now;
public DateTime? DeletedAt { get; set; }
}

You may want to consider using the default keyword to create an instance of any given type at runtime. However, with your given examples, your intentions may not simply be limited to avoiding unset properties.
Given that possibility, you could dynamically create the desired type and box/unbox it to trick the compiler - such as the example I've provided below.
This isn't generally recommended becuase of it's limited scope and general un-maintainability and error-pronedness.
You have other options as well such as creating generic instances using reflection, this may not be ideal since you have very specific "default" values that using reflection may just increase the complexity of the problem more than using a switch()(depending on your target framework, or if/else(like the example i've provided below.)
public class BaseEntity<T>
{
public T Id { get; set; } = (T)GetDefault<T>();
public DateTime? CreatedAt { get; set; } = DateTime.Now;
public DateTime? UpdatedAt { get; set; } = DateTime.Now;
public DateTime? DeletedAt { get; set; }
private static object GetDefault<U>()
{
Type paramType = typeof(U);
if(paramType == typeof(string))
{
return string.Empty;
}
else if(paramType == typeof(Guid))
{
return Guid.NewGuid();
}
return default(U);
}
}

Related

Method that takes two different objects

So i have two different objects, with different properties:
public class ModelA : IServices
{
public string Id { get; set; }
public ServiceType ServiceType { get; set; } (Enum)
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Limit { get; set; }
public int ChargePower { get; set; }
}
public class ModelB : IServices
{
public string Id { get; set; }
public ServiceType ServiceType { get; set; } (Enum)
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public int Power { get; set; }
}
I have then created an Interface:
public interface IServices
{
public string Id { get; set; }
public ServiceType ServiceType { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
And i then use this interface as a input parameter on my method:
public async Task EditObject(IServices serviceObject)
{
}
My problem now is that if i call the method with e.g ModelA, i can only use the properties that is inside my Interface, and yes that makes sense.
How can i make a method that can take both ModelA and ModelB and access the different properties inside these two objects?
Is generics the way to go? or do i have to make two different methods? or am i on the correct way with an Interface?
For instance i dont want ModelA to have ModelB:s property e.g "public int Power { get; set; }"
Hope you understand my question, cheers!
You can test, which class is it:
if (serviceObject is ModelA)
((ModelA)serviceObject).Limit = 5;
Or you can use Reflection:
PropertyInfo pi;
if ((pi = x.GetType().GetProperty("Limit")) != null)
pi.SetValue(x, 5);
Well, a lot of ways
You can make a method overload
public async Task EditObject(ModelA serviceObject) { }
public async Task EditObject(ModelB serviceObject) { }
or you could access needed type through upcasting it
var iServiceVariable = (IServices)new ModelA();
var modelBVariable = iServiceVariable as ModelB;
Console.WriteLine($"Is iServiceVariable of ModelB type? {modelBVariable != null}");
Or you could implement different behavior in your models using the same interface(doesn't have to be IServices), but accessing them in EditObject through the same way (what's the point of interface otherwise?)
If you want to do different things for multiple types, a fairly clean way to do it is by using a switch on the type:
switch(serviceObject)
{
case ModelA modelA:
modelA.Limit = 5;
break;
case ModelB modelB:
modelB.Power = 2;
break;
}

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,
});
}

Why the object is initialized at 0 as the default value in c #

I writes a code in c#.
using Entities...
all my Entities Object initialized at zero at their Primary Key field.
why does it happens?
and how I should uninitialized them?
I want them to get theirs id's in SQL...
here is my object:
public partial class Aircraft
{
public Aircraft()
{
Criterion = new HashSet<Criterion>();
Flight = new HashSet<Flight>();
}
public int AircraftId { get; set; }
public string AircraftName { get; set; }
public string Model { get; set; }
public DateTime? ProductionYear { get; set; }
public int? FirstRow { get; set; }
public int? LastRow { get; set; }
public string SeatsMapUrl { get; set; }
public virtual ICollection<Criterion> Criterion { get; set; }
public virtual ICollection<Flight> Flight { get; set; }
}
I create instance of it:
Aircraft aircraft = new Aircraft();
and while debugging this code
I found that the field - aircraftId (the Primary Key in SQL) - initialized at zero??
what should I to fix it?
Default value for int is 0. Integers are value types. If you need null as default value for AircraftId then you should change type to int?.
If auto generated value needed, then usually passing null will generate next value (depends on database and their types and/or triggers).

Prepopulate a Models property [duplicate]

This question already has answers here:
What is the best way to give a C# auto-property an initial value?
(23 answers)
Closed 5 years ago.
What i'm trying to do is create a new model that will have certain features:
public class GenericGoal
{
public int _id { get; set; }
public List<String> Type_of_Goal { get; set; }
public DateTime Date { get; set; }
}
my quick and small question would be, how would I prepopulate the Type_of_goal field?
You could use a constructor for this; could look like this example.
public class GenericGoal
{
public int _id { get; set; }
public List<String> Type_of_Goal { get; set; }
public DateTime Date { get; set; }
public GenericGoal()
{
Type_of_Goal = new List<String>();
}
}
I recommend the initialisation in the constructor because in my opinion it's cleaner and better readable.
You could give the property 'Type_of_Goal' an initial value, if you don't want to have to initialize it every time, or initialize it when no value is set to it.
public class GenericGoal
{
public int _id { get; set; }
public List<String> Type_of_Goal { get; set; } = new List<String>();
public DateTime Date { get; set; }
}
If it is 'NullReferenceException' you are concerned about, check for null's before accessing the 'Type_of_Goal' property, as follow. Note the ? - Known as Null Propagation Operator
genericGoalInstance.Type_of_Goal?.Add("Good Goal");

String was not recognized as a valid DateTime C#.net MVC

I am using MVC and cant find a solution to this error!
here is my model
Scorecard.cs
public partial class Scorecard
{
public int ScorecardID { get; set; }
public int VendorID { get; set; }
public string Title { get; set; }
public bool Enabled { get; set; }
public System.DateTime Created { get; set; }
public int CreatedBy { get; set; }
public Nullable<System.DateTime> LastUpdated { get; set; }
public Nullable<int> UpdatedBy { get; set; }
and my constructor in my ScorecardRepository.cs
//CONSTRUCTOR
public ScorecardRepository()
{
allScorecards = new List<Scorecard>();
scorecardData = XDocument.Load(HttpContext.Current.Server.MapPath("~/App_Data/ScorecardXML.xml"));
var scorecards = from scorecard in scorecardData.Descendants("item")
select new Scorecard((int)scorecard.Element("ScorecardID"), (int)scorecard.Element("VendorID"),
scorecard.Element("Title").Value, (bool)scorecard.Element("Enabled"),
(DateTime)scorecard.Element("Created"), (int)scorecard.Element("CreatedBy"),
(DateTime)scorecard.Element("LastUpdated"), (int)scorecard.Element("UpdatedBy"));
allScorecards.AddRange(scorecards.ToList<Scorecard>());
}
so everything works apart from a DateTime error i am getting which is really confusing me as to why it keeps happening...
ERROR
all help would be greatly appreciated
How about trying:
Convert.ToDateTime(scorecard.Element("Created").Value)
When reading data out of the XDocument, you need to parse the dates rather than cast:
DateTime.Parse(scorecard.Element("Created"))
Do you need to cast explicitly to XElement before the explicit cast to DateTime? i.e.:
(DateTime)(XElement)(scorecard.Element("Created")), ...
Your cast should work with a valid string but, having seen your XML, there are values in there that cannot be parsed into dates. You'll need to check for FormatExceptions when you convert, if the data are not always going to be valid.
You should never trust the input. Use TryParse before you cast anything into any other type except string. And you should check for null values (especially for nullable types). Should it still throw exceptions, they are better managed (by you).
Try this :
(DateTime)Convert.ToDateTime(scorecard.Element("Created").Value),
in
public ScorecardRepository()
{
}

Categories