I have designed a lot of models like this:
public class Book
{
public string Title { get; set; }
public int PageCount { get; set; }
public bool SecondHand { get; set; }
}
This kind of "incomplete" initialisation doesn't raise any compiler exceptions:
new Book
{
Title = "Welcome to the The"
}
But I would like it to error at compile time, because a few non-nullable fields (int not int?) are not initialised.
How can I design models so that, upon instantiation, failing to initialise their non-nullable fields throws errors at compile time?
(And prevents compilation)
I like using the new Book { ... } instantiation syntax, instead of a constructor new Book(...), because I can see all the field names laid out before me, very visibly.
If possible, I would like a solution that can preserve this.
You can require that the mandatory properties are set via a constructor. For example, if PageCount is mandatory:
public class Book
{
public Book(int pageCount)
{
this.PageCount = pageCount;
}
public string Title { get; set; }
public int PageCount { get; }
public bool SecondHand { get; set; }
}
Now you won't be able to instanciate an instance of Book without correctly initializing it.
Now you can say:
new Book(10)
{
Title = "Welcome to the The"
}
If you want to be more explicit then you can use named parameters:
new Book(pageCount : 10)
{
Title = "Welcome to the The"
}
In the example above, if you want to make PageCount modifiable after it has been initialized in the constructor then you can give it a public setter, but still require initialization via the constructor.
The only way to avoid this is disallowing the syntax altogher. This is feasable by simply avoiding the default constructor:
public class Book
{
public Book(string title, int PageCount, bool secondHand) { ... }
public string Title { get; set; }
public int PageCount { get; set; }
public bool SecondHand { get; set; }
}
Related
I am a newbie on C# and I am trying to make a program to handle orders from customers. I created my object and added a method to read the user input but I am still struggling with creating a list where user can add products by putting in their properties ( name, code and price).
Here is what I got so far :
public class Produit
{
public string? NomProduits { get; set; }
public string? CodeProduits { get; set; }
public string? PrixProduits { get; set; }
}
public class AttributsProduits
{
public static void AjouterProduits ()
{
Produit ReadProduits()
{
return new Produit()
{
NomProduits = Console.ReadLine(),
CodeProduits = Console.ReadLine(),
PrixProduits = Console.ReadLine(),
};
}
}
}
I created the object and its attributes, and added a method to read said attributes from the user. This is what I did for the list but Im getting an error CS1729 :
List<Produit> produits = new List<Produit>();
produits.Add(new Produit(NomProduits));
produits.Add(new Produit(CodeProduits));
produits.Add(new Produit(PrixProduits));
Can anyone help me with this please?
Adding objects to an existing list
You're trying to use a constructor which accepts a single value as a parameter:
new Produit(NomProduits)
But your class has no defined constructors (and therefor has only the default parameterless constructor):
public class Produit
{
public string? NomProduits { get; set; }
public string? CodeProduits { get; set; }
public string? PrixProduits { get; set; }
}
You can use the parameterless constructor:
new Produit()
Or perhaps specify the value in an object initializer:
new Produit { NomProduits = NomProduits }
Or define a constructor:
public class Produit
{
public string? NomProduits { get; set; }
public string? CodeProduits { get; set; }
public string? PrixProduits { get; set; }
public Produit(string nomProduits)
{
NomProduits = nomProduits;
}
}
Note that in the case of the constructor this explicitly defines which of the three properties are initialized by the constructor parameter. So your next two objects may not quite make sense. You could define constructors that take multiple parameters, use object initializers in each case, etc.
What logic you build is up to you. The point is that in order to use a specific constructor you need to first define that constructor.
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,
});
}
The sub class isn't derived from the main class, I'm just trying to differentiate them.
Even as I type this I can see it being impossible but I have some classes:
public class TransferServiceInformation {
public int ProviderId { get; set; }
public string PrePurchaseOverride { get; set; }
public bool PrePurchaseOverrideEnabled { get; set; }
}
and
public class TransferServiceProviderInformation {
public int ProviderId { get; set; }
public string PrePurchaseInfo { get; set; }
And I want it so that if I ever try to access myTransferServiceInformation.PrePurchaseOverride and PrePurchaseOverrideEnabled == false it should return PrePurchaseInfo from the TransferServiceProviderInformation with the same ID.
Is something like that even possible?
I'm just having a thought that a getter that requires a TransferServiceProviderInformation passed as an argument might work, and throw an exception if the IDs don't match. Is that the only solution? The thing is, I'd rather not have to dig through all the (thousands of lines of) code to change all the places were I (or someone else) has called this property.
This is just an idea:
Make a static list with instances inside your class and auto-fill it with using the constructor. Then you can check this list from outside for instances with the same id.
public class TransferServiceInformation
{
public int ProviderId { get; set; }
private string prePurchaseOverride;
public string PrePurchaseOverride
{
get
{
if(!PrePurchaseOverrideEnabled)
{
// Get instances from the other class where providerID matches
var instance = TransferServiceProviderInformation.Instances.Where(i => i.ProviderId == this.ProviderId).FirstOrDefault();
if(instance != null)
return (instance).PrePurchaseInfo;
}
return null; // If no match found
}
set
{
prePurchaseOverride = value;
}
}
private bool prePurchaseOverrideEnabled;
public bool PrePurchaseOverrideEnabled { get; set; }
}
public class TransferServiceProviderInformation
{
// Store your instances static
public static List<TransferServiceProviderInformation> Instances { get; set; }
public TransferServiceProviderInformation()
{
// Add every new instance to the list
Instances.Add(this);
}
public int ProviderId { get; set; }
public string PrePurchaseInfo { get; set; }
}
To-do's:
If an instance gets disposed, delete it from the list of instances.
I am looking at the LCOM metric as shown here,
http://www.ndepend.com/Metrics.aspx
So we are saying a few things,
1) A class is utterly cohesive if all its methods use all its instance fields
2) Both static and instance methods are counted, it includes also constructors, properties getters/setters, events add/remove methods
If I look at a class such as this,
public class Assessment
{
public int StartMetres { get; set; }
public int EndMetres { get; set; }
public decimal? NumericResponse { get; set; }
public string FreeResponse { get; set; }
public string Responsetype { get; set; }
public string ItemResponseDescription { get; set; }
public string StartText { get; set; }
public decimal? SummaryWeight { get; set; }
}
It gets a bad score of 0.94 because each getter and setter doesn't access 'all of the other instance fields'.
It is calculated like this,
accessAverage - methodCount / 1 - methodCount
(2 - 17) / (1 - 17) = 0.94 (rounded)
I am not understanding this metric, why should it include getters and setters? A getter and setter will always only access one single instance field.
This demonstrates that every software metric is flawed if you blindly take it to its extreme.
You know an "incohesive" class when you see one. For example:
class HedgeHog_And_AfricanCountry
{
private HedgeHog _hedgeHog;
private Nation _africanNation;
public ulong NumberOfQuills { get { return _hedgeHog.NumberOfQuills; } }
public int CountOfAntsEatenToday { get { return _hedgeHog.AntsEatenToday.Count(); } }
public decimal GrossDomesticProduct { get { return _africanNation.GDP; } }
public ulong Population { get { return _africanNation.Population; } }
}
This is obviously an incohesive class, because it contains two pieces of data that don't need to be with one another.
But while it's obvious to us that this class is incohesive, how can you get a software program to determine incohesion? How would it tell that the above class is incohesive, but this isn't?
class Customer
{
public string FullName { get; set; }
public Address PostalAddress { get; set; }
}
The metric they came up with certainly detects incohesion, but also comes up with false positives.
What if you decided this metric was important? You could create a "CustomerData" class containing just fields, and a "Customer" class that exposes the data fields as properties.
// This has no methods or getters, so gets a good cohesion value.
class CustomerData
{
public string FullName;
public Address PostalAddress;
}
// All of the getters and methods are on the same object
class Customer
{
private CustomerData _customerData;
public string FullName { get { return _customerData.FullName; } }
// etc
}
But if I'm playing this game, I can apply it to the incohesive example as well:
class Hedgehog_And_AfricanCountry_Data
{
public Hedgehog _hedgehog;
public AfricanNation _africanNation;
}
class Hedgehog_And_AfricanCountry
{
private Hedgehog_And_AfricanCountry_Data _hedgehogAndAfricanCountryData;
// etc;
}
Really, I think it's best to understand what cohesion is, and why it's a worthwhile goal, but also understand that a software tool can not properly measure it.
I have a number of classes that are all related conceptually, but some more-so at the details level than others. For example, these three classes have nearly identical properties (although member functions will vary):
public class RelatedA : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
}
public class RelatedB : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
}
public class RelatedC : IRelatedType
{
public string Name { get; set; }
public string Value { get; set; }
public DateTime Stamp { get; set; }
public int Special { get; set; }
}
There are a couple of other classes that are conceptually related to the above 3, but can be a bit different implementation-wise:
public class RelatedD : IRelatedType
{
public string Name { get; set; }
public string Statement { get; set; }
}
public class RelatedE : IRelatedType
{
public string Name { get; set; }
public string Statement { get; set; }
public bool IsNew { get; set; }
}
Instances of these can be created by a factory based on some sort of "type" enumerated value. The problem is that later on when these objects are being used (in a business layer, for example), there could be a lot of code like this:
IRelatedType theObject = TheFactory.CreateObject(SomeEnum.SomeValue);
if (theObject is RelatedC)
{
RelatedC cObject = theObject as RelatedC;
specialVal = cObject.Special;
}
else if (theObject is RelatedD)
{
RelatedD dObject = theObject as RelatedD;
statementVal = dObject.Statement;
}
else if (theObject is RelatedE)
{
RelatedE eObject = theObject as RelatedE;
statementVal = eObject.Statement;
isNewVal = eObject.IsNew;
}
This could be repeated in many places. Is there a better approach to the design that I should be using (there's got to be)?
You could try and factor the differences into seperate classes that are then provided so for example:
IRelatedType theObject = TheFactory.CreateObject(SomeEnum.SomeValue);
RelatedTypeHelper theHelper=TheFactory.CreateHelper(theObject);
theHelper.DoSpecialThing(theObject);
Now you won't have to have all the if else blocks, and if you add a new type which requires new handling, you just whip up a new helper implement the required pieces and you should be good to go. The helper should help document this process.
I would also question why a single method would have such a different implementation for specialVal and StatementVal could be your sample, but It makes me curious what your really doing here. can you simplify things back taking a step back and questioning the point of these being included in this specific hierarchy.