Foreach() with if statements not affecting variables - c#

I am trying to add an InventoryState to the various products extended from my IProduct interface I created before, but the foreach() statement I made to check the state of the inventory is not changing the default value of Unassigned on the property...
This is the properties for each product object:
public string ProductType
{
get { return "Apple"; }
set { }
}
public double BulkPrice
{
get { return 0.99; }
set { }
}
public double RetailPrice
{
get { return 1.49; }
set { }
}
public int Quantity
{
get { return 50; }
set { }
}
public int MaxQuantity
{
get { return 100; }
set { }
}
public InventoryState Status
{
get { return InventoryState.Unassigned; }
set { }
}
And these are the various declarations and the foreach in question:
public enum InventoryState
{
Full,
Selling,
Stocking,
Empty,
Unassigned
}
public interface IProduct
{
string ProductType { get; set; }
double BulkPrice { get; set; }
double RetailPrice { get; set; }
int Quantity { get; set; }
int MaxQuantity { get; set; }
InventoryState Status { get; set; }
}
public static IProduct[] ProductList =
{
new Apple(),
new Blueberry()
};
foreach (IProduct productName in ProductList) // broken- not being called :(?
{
if (productName.Quantity == productName.MaxQuantity)
{
productName.Status = InventoryState.Full;
return productName.Status;
}
else if (productName.Quantity <= (productName.MaxQuantity * (0.5)))
{
productName.Status = InventoryState.Stocking;
}
else if (productName.Quantity == 0)
{
productName.Status = InventoryState.Empty;
}
else
{
productName.Status = InventoryState.Selling;
}
}

You always do in your automatic properties
get { return "some value";}
Even if you assign a value to it, it will always return "some value" even if the underlying value is different.
Do this for all your properties:
public string ProductType
{
get; set;
} = "Apple";
They will have default value "Apple" but it will get assigned and returned correctly.
Note that auto property default value is only from C# 6.0 onward.
Otherwise you need a private backing field.

Related

Caught "Specified cast is not valid." error on receiving data in C# ASP.net MVC?

I'm new to Entity Framework. I was trying to get my data from my local database through this basic line of code, I wanted to store all of the objects in the "Object" row into a list.
But it seems like it doesn't work, whatever I try. I'm running SQL server, ASP.NET MVC. My code is something like these:
[HttpGet]
public List<Object> Function1()
{
List<Object> result = new List<Object>();
using (DatabaseContext db = new DatabaseContext())
{
result = db.Object.ToList();
// ...
return result;
}
}
It always ended up with "Specified cast is not valid." error:
This is where the error was caught:
Line 137: result = db.Object.ToList();
This is my model class, I added some functions though, but I haven't changed any default properties that Entity set up for me :
public partial class Object
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public int Like { get; set; }
public int View { get; set; }
public byte Level
{
get { return Level; }
set
{
if (value < 1 || value > 3)
{
Level = 1;
throw new Exception("Level must be in 1 to 3. By default, it becomes 1");
}
else
{
Level = value;
}
}
}
public string Introduction { get; set; }
public string VideoUrl { get; set; }
public string Tag { get; set; }
public string Steps { get; set; }
public DateTime Date { get; set; }
public Object(string name, byte level, string introduction = null)
{
this.Name = name;
this.Level = level;
this.Introduction = introduction;
}
}
Is it oke to add functions and fix the properties like that ??
This is my table design in sql : pic
You have used public byte Level auto-property with a custom setter method.
This should be accompanied with a private backing variable. Something like
private byte _level
public byte Level
{
get { return _level; }
set
{
if (value < 1 || value > 3)
{
_level = 1;
throw new Exception("Level must be in 1 to 3. By default, it becomes 1");
}
else
{
_level = value;
}
}
}
You need to case the Object into a specific Model object something like this
[HttpGet]
public List<Object> Function1()
{
List<Object> result = new List<Object>();
using (DatabaseContext db = new DatabaseContext())
{
//result = db.Object;
result = (from d in db.Object.ToList()
select new Object{
prop1 = d.prop1,
prop2 = d.prop2,
.......
}).ToList();
// ...
return result;
}
}

How can I update the value of a field in every row of a list?

I have this class:
public class Test
{
public string Id { get; set; }
public int Number { get; set; }
public int DoubleNumber { get; set; }
}
and a list
List<Test> myTestList;
How can I make the value of the field DoubleNumber in myTestList equal to twice the value of Number? Note that I am okay to create another list if that's needed.
If I understand your question correctly:
foreach(Test item in myList) {
item.DoubleNumber = 2*item.Number;
}
Or, if it's ok, just remove the setter and modify the getter to return 2x Number:
public class Test
{
public string Id { get; set; }
public int Number { get; set; }
public int DoubleNumber { get { return 2* this.Number; } } //completely remove setter
}
Or, if you still want to be able to modify DoubleNumber:
public class Test {
private int m_num;
private int m_doubleNum;
public string Id {
get;
set;
}
public int Number {
get {
return this.m_num;
}
set {
this.m_num = value;
this.m_doubleNum = 2 * value; //when Number is set, update m_doubleNum too
}
}
public int DoubleNumber {
get {
return this.m_doubleNum;
}
set {
this.m_doubleNum = value; //allow manual setting of DoubleNumber
//or maybe also modify Number here?
//this.m_num = value / 2;
}
}
}
One way it could be using a foreach statement:
foreach(var item in myTestList)
{
item.DoubleNumber = 2*item.Number;
}
Another way it could be to use LINQ.
var result = myTestList.Select(test => new Test
{
test.Id,
test.Number,
DoubleNumber = 2*test.Number;
})
.ToList();
Among the two ways I would prefer the first one, since it's more clear what you are trying to do and more performant (in the second approach you have to create a new object for each object in myTestList).

C# validate model by mapping values of multiple Lists

I need to run validation on JSON input model by taking the value from one List and check if it exists in another. This value is a rating is from 1 - 5. If there is no matching number, then it should throw an error. Below is the code and this logic goes in the section commented with : //check if rating exist in score table
namespace Alpha.Model
{
// INPUT
public class AlphaCalcParamMethod
{
public ICollection<PortfolioInputModel> portfolios { get; set; }
public Setting settings { get; set; }
public bool Validation(ref string errString)
{
// Check if portfolio exists
if(portfolios == null || portfolios.Count < 1)
{
errString = "At least 1 Portfolio.";
return false;
}
//check if weight adds upto 1
foreach(var portfolio in portfolios)
{
// var holdings = new List<PortfolioHoldingInput>();
var weightAggregator = 0.00;
foreach(var holding in portfolio.portfolioHoldings)
{
weightAggregator += holding.fundWeight;
}
if (weightAggregator != 1)
{
errString = "Fund Weights should add upto 1";
}
return false;
}
//check if rating exist in score table
foreach(var portfolio in portfolios)
{
var holdings = new List<PortfolioHoldingInput>();
var scores = new List<Setting>();
foreach(var holding in holdings)
{
//fetch the value of fundRating double
foreach(var score in scores)
{
//check if the value above exist in grossAlpha's List fundRating
// if it doesn't return false
}
}
return false;
}
return true;
}
}
// OUTPUT
public class AlphaCalcResultMethod
{
public List<PortfolioOutputModel> portfolios { get; set; }
}
public class PortfolioInputModel
{
public string portfolioIdentifier { get; set; }
public ICollection<PortfolioHoldingInput> portfolioHoldings { get; set; }
}
public class PortfolioOutputModel
{
public string portfolioIdentifier { get; set; }
public double portfolioAlpha { get; set; }
public ICollection<PortfolioHoldingOutput> portfolioHoldings { get; set; }
}
public class PortfolioHoldingInput
{
public string fundIdentifier { get; set; }
public int fundRating { get; set; }
public double fundExpenseRatio { get; set; }
public double fundWeight { get; set; }
}
public class PortfolioHoldingOutput
{
public string fundIdentifier { get; set; }
public int fundRating { get; set; }
public double fundExpenseRatio { get; set; }
public double fundWeight { get; set; }
public double fundAlpha { get; set; }
}
public class Setting
{
public List<GrossAlpha> grossAlphas { get; set; }
}
public class GrossAlpha
{
public int fundRating { get; set; }
public double grossAlpha { get; set; }
}
}
If you are going to return additional values from method, you should use out parameters.
Don't specify type of variable in variable name. I.e. instead of errorString just use error. Hungarian notation and other tricks are not needed with modern IDEs.
Double type is not precise. You should avoid comparing it to integer values for equality. Prefer greater or less than comparisons.
Use LINQ to replace loops
Method name Validation is a noun. That is pretty confusing for method which is action and should a verb. Consider rename it to Validate or IsValid
Code
public bool IsValid(out string error)
{
if (portfolios?.Any() == false)
{
error = "At least 1 Portfolio.";
return false;
}
if (portfolios.Any(p => p.portfolioHoldings.Sum(h => h.fundWeight) < 1))
{
error = "Fund Weights should add upto 1";
return false;
}
var holdings = portfolios.SelectMany(p => p.portfolioHoldings);
var validRatings = new List<int> { 1, 2, 3, 4, 5 };
if (holdings.Any(h => !validRatings.Contains(h.fundRating)))
{
error = "Fund ratings should be in " + String.Join(",", validRatings);
return false;
}
error = "";
return true;
}
Note: if valid ratings are sequential numbers, then you can just check range of fundRating value:
if (holdings.Any(h => h.fundRating < 1 || 5 < h.fundRating))
Look this code:
if(!score.grossAlphas.Exists(x => x.fundRating == holding.fundRating))
{
return false;
}
it check if exists grossAlphas with fundRating equals holding.fundRating.
put it in the loop where you want to check, let me know if it is what you want and if it works.

C# DynamoDB Query a nested property using LINQ

I've the MyTableItem class that maps a DynamoDB table.
I need to implements the GetMyTableItemsWithoutFinalStatus method that query the table by specific filters on nested property of a custom type, MyStatus.
The filter has to check if:
there's no status
status is not initialized
there's no "final" status in the status list
date is greater than today - daysFromNow
So my conditions in OR are:
StatusCount == 0
Status == null
Status.Where(s => s.Status != StatusEnum.DELIVERED).Count == 0
Date > DateTime.UtcNow.AddDays(-daysFromNow)
Actually I need to get back all the items that has no status or no final status, because I've to update them.
How can I implement the condition on nested property of MyStatus object?
This is my code
[Serializable]
public class MyTableItem
{
[DynamoDBHashKey]
public string Id { get; set; }
[DynamoDBProperty]
public string Field1 { get; set; }
[DynamoDBProperty]
public string Field2 { get; set; }
[DynamoDBProperty]
[DynamoDBGlobalSecondaryIndexRangeKey]
public DateTime Date { get; set; }
// My complex object
[DynamoDBProperty(typeof(MyStatusConverter))]
public MyStatus Status { get; set; }
[DynamoDBProperty]
public int StatusCount { get { return Status.Count; } set { value = Status.Count; } }
}
[Serializable]
public class MyStatus : IList<MyState>
{
private readonly IList<MyState> stateList = new List<MyState>();
public PeppolDespatchAdviceState this[int index]
{
get { return stateList[index]; }
set { stateList.Insert(index, value); }
}
public int Count
{
get { return stateList.Count; }
}
public bool IsReadOnly
{
get { return stateList.IsReadOnly; }
}
// IList interface implementation...
}
[Serializable]
public class MyState
{
public string DocumentType { get; set; }
public string Status { get; set; }
public string SkipCause { get; set; }
public DateTime Date { get; set; }
}
public enum StatusEnum
{
DEFAULT,
CREATED,
DELIVERED,
UNDELIVERABLE,
RE_RECEIVED
}
#region Converter definition
public class MyStatusConverter : IPropertyConverter
{
public DynamoDBEntry ToEntry(object value)
{
// Implementation...
}
public object FromEntry(DynamoDBEntry entry)
{
// Implementation...
}
#endregion
public IList<MyTableItem> GetMyTableItemsWithoutFinalStatus(long id, int daysFromNow = 3)
{
try
{
List<MyTableItem> items = new List<MyTableItem>();
DynamoDBOperationConfig operationConfig = new DynamoDBOperationConfig();
operationConfig.OverrideTableName = "MyTableName";
operationConfig.IndexName = "MyIndex";
List<ScanCondition> conditions = new List<ScanCondition>();
conditions.Add(new ScanCondition(MyTableItemTableAttributes.StatusCount, ScanOperator.Equal, 0));
conditions.Add(new ScanCondition(MyTableItemTableAttributes.Status, ScanOperator.IsNull));
// Here I need to add a LINQ condition: Status.Where(s => s.Status != StatusEnum.DELIVERED).Count == 0 )
conditions.Add(new ScanCondition(MyTableItemTableAttributes.Date, ScanOperator.GreaterThan, DateTime.UtcNow.AddDays(-daysFromNow)));
operationConfig.QueryFilter = conditions;
operationConfig.ConditionalOperator = ConditionalOperatorValues.Or;
DynamoDBContext context = new DynamoDBContext(DynamoDBClient);
items = context.Query<MyTableItem>(id, operationConfig).ToList();
return items;
}
catch (Exception ex)
{
throw;
}
}

How to use the Same Class on Client as on the Service?

How can I pass an entire defined class through a WCF service? I have the class defined on both the service and client side. I keep getting an error:
Best overloaded method match has some invalid arguments.
The whole class was copied from the client-side to the service-side.
Client side calling:
TransferProxy.PutTransferOnService(Transfer);
Defined on service:
[OperationContract]
bool PutTransferOnService(TypeTransfer Transfer);
I don't want to access individual items on the class from the client, I just want to move the WHOLE populated object through and do processing on the server side.
[DataContract]
public class TypeTransfer
{
private string userID;
private string transferNum;
private DateTime effectiveDate;
private int unitCount;
private int skuCount;
private string reason;
private string localStatus;
private string destStatus;
private string carrier;
private string sourceStore;
private string destinationStore;
private string inSeal;
private string outSeal;
[DataMember]
private List<TypeSOQ> correspondingSOQ = new List<TypeSOQ>();
[DataMember]
private List<TypeProductList> ProductList = new List<TypeProductList>();
public TypeTransfer() { }
// Function adds single item to transfer object
public void AddItem(int ProductID, string SKU, string PrimarySKU, string SCC, string ProductDescription, int TransferQty)
{
ProductList.Add(new TypeProductList
{
productID = ProductID,
sku = SKU,
primaryUPC = PrimarySKU,
scc = SCC,
description = ProductDescription,
transferQty = TransferQty
});
}
// Add SOQ to transfer object (can support multiple SOQ's)
public void AddSOQ(TypeSOQ soq)
{
correspondingSOQ.Add(soq);
}
// Function returns number of skus in Product List
public int GetSKUTotal()
{
return ProductList.Count();
}
// Function returns total number of items in transfer
public int GetItemTotal()
{
int itemtotal = 0;
for (int i = 0; i < ProductList.Count(); i++)
{
itemtotal += ProductList[i].transferQty;
}
return itemtotal;
}
// Return entire SOQ list
public List<TypeSOQ> GetSOQs()
{
return correspondingSOQ;
}
// Returns full product list in transfer object
public List<TypeProductList> GetProductList()
{
return ProductList;
}
[DataMember]
public string UserID
{
get { return userID; }
set { userID = value; }
}
[DataMember]
public string TransferNum
{
get { return transferNum; }
set { transferNum = value; }
}
[DataMember]
public DateTime EffectiveDate
{
get { return effectiveDate; }
set { effectiveDate = value; }
}
[DataMember]
public int UnitCount
{
get { return unitCount; }
set { unitCount = value; }
}
[DataMember]
public string Reason
{
get { return reason; }
set { reason = value; }
}
[DataMember]
public string LocalStatus
{
get { return localStatus; }
set { localStatus = value; }
}
[DataMember]
public string DestStatus
{
get { return destStatus; }
set { destStatus = value; }
}
[DataMember]
public string Carrier
{
get { return carrier; }
set { carrier = value; }
}
[DataMember]
public string SourceStore
{
get { return sourceStore; }
set { sourceStore = value; }
}
[DataMember]
public string DestStore
{
get { return destinationStore; }
set { destinationStore = value; }
}
[DataMember]
public string InSeal
{
get { return inSeal; }
set { inSeal = value; }
}
[DataMember]
public string OutSeal
{
get { return outSeal; }
set { outSeal = value; }
}
[DataMember]
public int SKUCount
{
get { return skuCount; }
set { skuCount = value; }
}
}
You said - The whole class was copied from the client-side to the service-side.
You don't need to copy your class to server side. just define your class in a separate library and give reference of that same library to both client and server.

Categories