Generate unique string key based on properties of object (cachekey) - c#

I am simply trying to generate a unique cachekey that takes in the object type and property values
GetHashCode returns different results each time so that wont work, so I have to implement a solution but it has to be fast (I can go through the properties and and concat their values to a string but this might be slow and not the best way to go about it)
Nice To Have:
so if 2 different object types have the exact same properties and same values but they are different classes, they should be different cachekeys (chances of this happening are very slim but just in case)
Here is my code
public interface ICachableRequest
{
string GetCacheKey();
}
public class Object1 : ICachableRequest
{
public int IntValue1 { get; set; }
public double DoubleVal1 { get; set; }
public string StringVal1 { get; set; }
public string GetCacheKey()
{
throw new NotImplementedException();
}
}
public class Object2 : ICachableRequest
{
public int SomeIntValue1 { get; set; }
public double SomeOtherDoubleVal1 { get; set; }
public string MoreStringVal1 { get; set; }
public string MoreStringVal2 { get; set; }
public string MoreStringVal3 { get; set; }
public string MoreStringVal4 { get; set; }
public string GetCacheKey()
{
throw new NotImplementedException();
}
}

Related

How to initialize an array in a property's sub-class? (Object reference not set.... error)

First of all, please stick to how I accomplish this with the current setup, and not in trying to redesign how it is structured. I have to build an app/web service to receive a JSON query. The JSON is generated by a widget that we can not customize. I used Visual Studio to create the class structure from a JSON example.
I want to test my service, and I'm getting errors in SOAPUI, so I need something where I can debug, so I'm hard-coding the JSON input object for my Service Reference.
Here are the classes, as they reside on the web service -
[DataContract]
public class QuoterIn
{
[DataMember]
public Quoterinput quoterinput { get; set; }
}
public class Quoterinput
{
public string agent_id { get; set; }
public string key { get; set; }
public string auto_assign { get; set; }
public Consumer consumer { get; set; }
public string viaEmail { get; set; }
}
public class Consumer
{
public string brand_id { get; set; }
public string full_name { get; set; }
public Addresses_Attributes[] addresses_attributes { get; set; }
public string birth_or_trust_date { get; set; }
public string gender { get; set; }
public Emails_Attributes[] emails_attributes { get; set; }
public Phones_Attributes[] phones_attributes { get; set; }
public Cases_Attributes[] cases_attributes { get; set; }
}
public class Addresses_Attributes
{
public string zip { get; set; }
}
public class Emails_Attributes
{
public string value { get; set; }
}
public class Phones_Attributes
{
public string value { get; set; }
}
public class Cases_Attributes
{
public Quoting_Details_Attributes[] quoting_details_attributes { get; set; }
}
public class Quoting_Details_Attributes
{
public string carrier_id { get; set; }
public string duration_id { get; set; }
public string policy_type_id { get; set; }
public string plan_name { get; set; }
public string product_type_name { get; set; }
public string face_amount { get; set; }
public string carrier_health_class { get; set; }
public string planned_modal_premium { get; set; }
public string premium_mode_id { get; set; }
public string health_class_id { get; set; }
}
Looking at the sub-class of Consumer, there are several sub-classes that are arrays - address_attributes, phone_attributes, and email_attributes.
I'm able to initialize the main JSON input/inquiry container, and then I can initialize the main class and the sub-class of "Consumer." I can enter data for the main fields, and then fields in the sub-class of Consumer, but I can't initialize the arrays.
Here's the code up until this point for populating that input container -
protected void btnRun_Click(object sender, EventArgs e)
{
QuoterIn req = new QuoterIn();
req.quoterinput = new Quoterinput();
req.quoterinput.consumer = new Consumer();
req.quoterinput.agent_id = "1938";
req.quoterinput.key = "afasdfasdfasdfasdfasd";
req.quoterinput.auto_assign="true";
req.quoterinput.consumer.brand_id = "21264";
req.quoterinput.consumer.full_name = "Fred Smith";
req.quoterinput.consumer.addresses_attributes[0].zip = "53704";
.................(more code like this, but this last line is where the program fails)
Since we aren't going to take in multiple email addresses or phone numbers, I'd be fine with not having it be an array, but I'm worried that the incoming JSON with all the grouping and bracketing will fail if it's not set up like an array. I've tried to initialize instance zero like this -
req.quoterinput.consumer.addresses_attributes[0] = new Addresses_Attributes();
.... and Visual Studio likes the code syntax-wise, but it doesn't initialize an instance when it runs, and then I get the "Object reference not set to an instance of an object." error when it runs. It hasn't allowed me to initialize the array using more generic methods since it has to map to this specific property we've already declared.
I have no doubt it's probably straightforward, but I'm not all that experienced in manipulating arrays and lists like this, and I haven't been able to find examples of arrays of sub-classes within subclasses of properties.
Just instantiate / assign the address at the same time. Something like this should work:
req.quoterinput.consumer.addresses_attributes = new []
{
new Addresses_Attributes
{
zip = "53704"
}
};
Another way (since the property toy are trying to set is an Array), is to create a dynamic sized list, add to it, then convert it back during declaration.
var addresses = new List<Addresses_Attributes>
{
new Addresses_Attributes {zip = "53704"}
};
req.quoterinput.consumer.addresses_attributes = addresses.ToArray();
Or, you can assign it an array of size 1, and then set it up from there:
req.quoterinput.consumer.addresses_attributes = new Addresses_Attributes[1];
req.quoterinput.consumer.addresses_attributes[0] = new Addresses_Attributes { zip = "666" };

How to populate object with another object with almost same structure? [duplicate]

This question already has answers here:
copy chosen properties to object of other type
(2 answers)
How to cast between 2 types of the same name and internal sturcture but from different assemblies?
(5 answers)
Copy two identical object with different namespaces (recursive reflection)
(7 answers)
Closed 2 years ago.
I'm trying to find the best way to populate my constructor with another constructor that have almost the same structure without setting each attribute,
So i have constructor Altridatiidentificativi in ModelRA constructor:
public class Altridatiidentificativi
{
public string denominazione { get; set; }
public string indirizzo { get; set; }
public string numeroCivico { get; set; }
public string cap { get; set; }
public string comune { get; set; }
public string provincia { get; set; }
public string nazione { get; set; }
public bool modificati { get; set; }
public string defAliquotaIVA { get; set; }
public bool nuovoUtente { get; set; }
}
And Altridatiidentificativi in Documenti:
public class Altridatiidentificativi
{
public bool nuovoUtente { get; set; }
public string denominazione { get; set; }
public string indirizzo { get; set; }
public string numeroCivico { get; set; }
public string cap { get; set; }
public string comune { get; set; }
public string provincia { get; set; }
public string nazione { get; set; }
}
As you can see the structure is almost the same, just constructor in ModelRA has this two extras modificati and defAliquotaIVA
So i was wondering if it's possible in some way to pass inside ModelRA.Altridatiidentificativi the Documenti.Altridatiidentificativi and then add the value to the extras
I was trying to do something like this :
public ModelRA initializeRA(Documento documento)
{
ModelRA model = new ModelRA();
model.altriDatiIdentificativi = <Altridatiidentificativi>(documento.altriDatiIdentificativi);
model.altriDatiIdentificativi.defAliquotaIVA = "";
model.altriDatiIdentificativi.modificati = false;
return model;
}
but i get error in <Altridatiidentificativi> "it's a type not a valid constructor in specific context"
Is there a way to reach what i'm trying to do or i have to set all the attributes manually?
Usually this pattern is a signal that there's a concept in your business model that needs to be abstracted into a composable pattern. The ModelRA.Altridatiidentificativi class could look like:
public class Altridatiidentificativi
{
public ModelRA.Altridatiidentificativi ModelRAAltridatiidentificativi { get; set; }
public bool modificati { get; set; }
public string defAliquotaIVA { get; set; }
}
Then your initialization code could look like this:
public ModelRA initializeRA(Documento documento)
{
ModelRA model = new ModelRA();
model.altriDatiIdentificativi.ModelRAAltridatiidentificativi = documento;
model.altriDatiIdentificativi.defAliquotaIVA = "";
model.altriDatiIdentificativi.modificati = false;
return model;
}
Tangentially I should mention that it's usually good practice to use property initializers and constructors unless you have a specific reason that you need initialization methods.
public class Altridatiidentificativi
{
public string ModelRA.Altridatiidentificativi ModelRAAltridatiidentificativi { get; set; }
public bool modificati { get; set; } = false; // unnecessary: this is default.
public string defAliquotaIVA { get; set; } = "";
public Altridatiidentificativi(ModelRA.Altridatiidentificativi modelRAAltridatiidentificativi)
{
this.modelRAAltridatiidentificativi = ModelRAAltridatiidentificativi;
}
}

C# Accessing a methods value dynamically using a string

I am currently setting some strings via this method:
string marketlabel = allmarketdata.#return.markets.COLXPM.label.ToString();
I would like to set the market label dynamically by having a string for the actual market choice.
string currentMarketSelected= this.marketTextBox.Text; // Specific market: COLXPM
string marketlabel=allmarketdata.#return.markets.currentMarketSelected.label.ToString();
I have been searching for a few hours and probably am not explaining correctly. I tried some stuff with reflections with no success. Basically what I want to do is have a textbox or list which contains all the market names and based on which one is selected start setting the data.
Above is the best type of example of what I want to do even though it is not syntactically possible to use a variable in place.
public class Markets
{
public COLXPM COLXPM { get; set; }
//Lots of markets below here
}
public class COLXPM
{
public string marketid { get; set; }
public string label { get; set; }
public string lasttradeprice { get; set; }
public string volume { get; set; }
public string lasttradetime { get; set; }
public string primaryname { get; set; }
public string primarycode { get; set; }
public string secondaryname { get; set; }
public string secondarycode { get; set; }
public List<Recenttrade> recenttrades { get; set; }
public List<Sellorder> sellorders { get; set; }
public List<Buyorder> buyorders { get; set; }
}
public class Return
{
public Markets markets { get; set; }
}
public class RootObject
{
public int success { get; set; }
public Return #return { get; set; }
}
The proposed solution below that worked
string currentMarketSelected = "DOGEBTC"; // Just selecting one of the markets to test it works
var property = allmarketdata.#return.markets.GetType().GetProperty(currentMarketSelected);
dynamic market = property.GetMethod.Invoke(allmarketdata.#return.markets, null);
string marketlabel = market.label.ToString(); //Gets all my selected market data
Here is a solution using reflection.
string currentMarketSelected= this.marketTextBox.Text; // Specific market: COLXPM
var property = allmarketdata.#return.markets.GetType().GetProperty(currentMarketSelected);
dynamic market = property.GetGetMethod().Invoke(allmarketdata.#return.markets, null);
string marketlabel=market.label.ToString();
You need something like this:
public class Markets
{
public COLXPM this[string key]
{
get
{
COLXPM colxpm;
switch (key)
{
// TODO : use "key" to select instance of COLXPM;
case "example1":
colxpm = ...;
break;
default:
throw new NotSupportedException();
}
return colxpm;
}
}
}
Then you can do something like:
string marketlabel=allmarketdata.#return.markets[currentMarketSelected]label.ToString();
This is an indexed property.

C# template methods for template IEnumerable<T>. Is it possible?

Can anybody help me to solve this problem?
I have a base class:
public class BaseShowFilter {
public int TotalCount { get; set; }
public int FromNo { get; set; }
public int ShowCount { get; set; }
public string SortFieldName { get; set; }
public bool SortAsc { get; set; }
}
and a couple of ChildClasses from this base class. Then I have a few of other classes that store in (for example)
IEnumerable<OtherClassXXX> = ....
And I want to apply some filter to all of them using same method implemented in BaseShowFilter:
For example I need
dstList = srcList.Skip(this.FromNo-1).Take(this.ShowCount);
So I need implement in BaseShowFilter one function that will be accept in parameter IEnumerable and will return also IEnumerable
How can I write it? In pure C++ it will be simple as 1,2,3... but here I don't know how can it be done. Result may be something like this:
public class BaseShowFilter {
public int TotalCount { get; set; }
public int FromNo { get; set; }
public int ShowCount { get; set; }
public string SortFieldName { get; set; }
public bool SortAsc { get; set; }
public T FilterList<T>(T SrcList) where T :IEnumerable<> {
return srcList.Skip(this.FromNo-1).Take(this.ShowCount);
}
}
This is the usual way to do it:
public IEnumerable<T> FilterList<T>(IEnumerable<T> source)
{
return source.Skip(this.FromNo - 1).Take(this.ShowCount);
}

Updating List<T> in DbContext

I have a Model like this
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<string> SolvedBy { get; set; }
}
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
}
and then Controller like this. But I cannot update the List "SolvedBy", the next time I step through with the debugger, the list is still empty.
[HttpPost]
public string Index(string flag = "", int id=0)
{
Challenge challenge = db.Challenges.Find(id);
if (flag == challenge.Flag)
{
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<string>();
}
chall.SolvedBy.Add(User.Identity.Name);
db.Entry(chall).State = EntityState.Modified;
db.SaveChanges();
//congrats, you solved the puzzle
return "got it";
}
else
{
return "fail";
}
}
is there any way around it to make a list of strings kept in the database?
EF don't know how to store an array in database table so it just ignore it. You can create another table/entity or use XML/JSON to store the list. You can serialize the list before saving and deserialize it after loading from database
A List<T> in a model would normally map to a second table, but in your DbContext you only have a single table. Try adding a second table.
public class ChallengeDBContext : DbContext
{
public DbSet<Challenge> Challenges { get; set; }
public DbSet<Solution> Solutions {get; set;}
}
public class Challenge
{
public int ID { get; set; }
public string Name { get; set; }
public string Blurb { get; set; }
public int Points { get; set; }
public string Category { get; set; }
public string Flag { get; set; }
public List<Solution> SolvedBy { get; set; }
}
public class Solution
{
public int ID { get; set; }
public string Name { get; set; }
}
Then your controller can use code along the lines of...
var chall = db.Challenges.Find(id);
if (chall.SolvedBy == null)
{
chall.SolvedBy = new List<Solution>();
}
chall.SolvedBy.Add(new Solution {Name=User.Identity.Name});
None of the above has been tested and I may have made some mistakes there, but the general principle I want to illustrate is the fact that you need another table. The List<T> represents a JOIN in SQL.

Categories

Resources