How to pass a Method with parameters to another method - c#

I'm trying to build up a Data Matrix which comprises a list of objects. So here's what I am trying to do:
List<IBasePremium> BasePremiumMatrix = new List<IBasePremium>();
List<ICalcRate> calcRates = new List<ICalcRate>
{
new CalcRate { BasePremiumType = 1, Rate = basePremiumRate.Building, Calc = basePremiumRate.Building },
new CalcRate { BasePremiumType = 2, Rate = basePremiumProduct.Building,Calc = calculator.BasePremium(basePremiumProduct.Building,basePremiumRate.Building) }
// new CalcRate { BasePremiumType = 3, Rate = (decimal)postcodeMultiplier.BuildingsCore ,Calc = calculator.BasePremium(postcodeMultiplier.BuildingsCore, ) },
};
on my line of code that is commented out, as the second parameter I really want to pass the value of 'Calc' from the previous line of code. I've got a number of lines like this where I need to pass the previous 'Calc' value to build the matrix. The above is clearly the wrong approach and thought that I'd be able to write a method that takes the form something like :
public CalcRate Multiplier(Func<string,decimal>, int basePremiumType, decimal rate) {.....}
But I'm fighting witrh passing the method name and it's parameter values.

Create and Action or a Func :
Action customAction = ()=> yourFunctionName(param1, param2);
then pass it to the multiplier.
var calcul = Multiplier(customAction , ....);

How about a for loop?
List<IBasePremium> BasePremiumMatrix = new List<IBasePremium>();
List<ICalcRate> calcRates = new List<ICalcRate>();
for (int i = 1; i < max; i++) {
CalcRate rate = new CalcRate { BasePremiumType = i , Rate = basePremiumRate.Building };
if ( i > 1) {
rate.Calc = calcRates.get(i - 2)
} else {
rate.Calc = calculator.BasePremium(basePremiumProduct.Building,basePremiumRate.Building);
}
calcRates.add(rate);
}

Related

C# - How to filter list using enum

I have 2 a classes:
public enum ArticleType
{
News = 1;
SpecialOffer = 2;
Service = 3;
}
public ArticleApiDto
{
public int Id;
public ArticleType Type;
}
Now i have method for getting data from db, something like:
public List<ArticleApiDto> GetAll(List<ArticleType> types)
{
var res = new List<ArticleApiDto>();
res = context.articles.ToList();
//do stuff
}
Now I would like to filter out Articles from res whose type is specified in types from parameter of method.
Problem 1: I actually cant use Contains because ArticleType is enum
Problem 2: List<ArticleType> is because sometimes i want to pass only one type but sometimes two or three. At the moment i cant figure out better better solution.
Can someone help me with this please I was searching for whole noone but cant figure out
To be able to pass more than one type you can do it like:
Make your enum to be Flags (note that values now can't be 1,2,3,4 and should be 1,2,4,8,16,...:
[Flags]
public enum ArticleType
{
News = 1;
SpecialOffer = 2;
Service = 4;
}
Now you add up what you want to filter with |:
filter = ArtickeType.News | ArticleType.Service;
var result = res.Where(x => filter & x.Type != 0).ToList();
or:
filter = ArtickeType.News | ArticleType.Service | ArticleType.SpecialOffer;
var result = res.Where(x => filter.HasFlag(x.Type)).ToList();
To do it with your current enum:
public enum ArticleType
{
News = 1;
SpecialOffer = 2;
Service = 3;
}
var filter = new List<ArticleType> { ArticleType.Service, ArticleType.News};
var result = res.Where(x => filter.Contains(x.Type)).ToList();
This code work with me, I use Linq with contains it may solve your problem.
public static List<ArticleApiDto> GetAll(List<ArticleType> types)
{
var res = new List<ArticleApiDto>();
List<ArticleApiDto> articles = new List<ArticleApiDto>
{
new ArticleApiDto{Id = 1, Type = ArticleType.News },
new ArticleApiDto{Id = 2, Type = ArticleType.SpecialOffer },
};
var newArticales = articles.Where(i =>
{
return types.Contains(i.Type);
}).ToList();
return newArticales;
}

How can I access multi-element List data stored in a public class?

My first question on SO:
I created this public class, so that I can store three elements in a list:
public class myMultiElementList
{
public string Role {get;set;}
public string Country {get;set;}
public int Commonality {get;set;}
}
In my main class, I then created a new list using this process:
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
I've added data to EmployeeRolesCountry and have validated that has 472 lines. However, when I try to retrieve it as below, my ForEach loop only retrieves the final line added to the list, 472 times...
foreach (myMultiElementList tmpClass in EmployeeRolesCountry)
{
string d1Value = tmpClass.Role;
Console.WriteLine(d1Value);
string d2Value = tmpClass.Role;
Console.WriteLine(d2Value);
int d3Value = tmpClass.Commonality;
Console.WriteLine(d3Value);
}
This was the most promising of the potential solutions I found on here, so any pointers greatly appreciated.
EDIT: adding data to EmployeeRolesCountry
/*
Before this starts, data is taken in via a csvReader function and parsed
All of the process below is concerned with two fields in the csv
One is simply the Country. No processing necessary
The other is bio, and this itself needs to be parsed and cleansed several times to take roles out
To keep things making sense, I've taken much of the cleansing out
*/
private void File_upload_Click(object sender, EventArgs e)
{
int pos = 0;
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
int a = 0;
delimiter = ".";
string token;
foreach (var line in records.Take(100))
{
var fields = line.ToList();
string bio = fields[5];
string country = fields[4];
int role_count = Regex.Matches(bio, delimiter).Count;
a = bio.Length;
for (var i = 0; i < role_count; i++)
{
//here I take first role, by parsing on delimiter, then push back EmployeeRolesCountry with result
pos = bio.IndexOf('.');
if (pos != -1)
{
token = bio.Substring(0, pos);
string original_token = token;
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
a = original_token.Length;
bio = bio.Remove(0, a + 1);
}
}
}
}
EDIT:
When grouped by multiple properties, this is how we iterate through the grouped items:
var employeesGroupedByRolwAndCountry = EmployeeRolesCountry.GroupBy(x => new { x.Role, x.Country });
employeesGroupedByRolwAndCountry.ToList().ForEach
(
(countryAndRole) =>
{
Console.WriteLine("Group {0}/{1}", countryAndRole.Key.Country, countryAndRole.Key.Role);
countryAndRole.ToList().ForEach
(
(multiElement) => Console.WriteLine(" : {0}", multiElement.Commonality)
);
}
);
__ ORIGINAL POST __
You are instantiating rc1 only once (outside the loop) and add the same instance to the list.
Please make sure that you do
var rc1 = new myMultiElementList();
inside the loop where you are adding the elements, and not outside.
All references are the same in your case:
var obj = new myObj();
for(i = 0; i < 5; i++)
{
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
now the list has 5 elements, all pointing to the obj (the same instance, the same object in memory), and when you do
obj.Prop1 = "Prop" + 5
you update the same memory address, and all the pointers in the list points to the same instance so, you are not getting 472 copies of the LAST item, but getting the same instance 472 times.
The solution is simple. Create a new instance every time you add to your list:
for(i = 0; i < 5; i++)
{
var obj = new myObj();
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
Hope this helps.

C# mimic associative array of unknown key-number (like in PHP)

Is there a possibility to create sth. like an associative array like in PHP?
I don't plan to create a game with some player-data, but I could easily explain this way what I want:
player["Name"] = "PName";
player["Custom"]["Gender"] = "Female";
player["Custom"]["Style"] = "S1";
player["Custom"]["Face"]["Main"] = "FM1";
player["Custom"]["Face"]["Eyes"] = "FE1";
player["Custom"]["Height"] = "180";
Also the length has to be dynamic, I don't how many keys there will be:
player["key1"]["key2"]=value
player["key1"]["key2"]["key3"]["key4"]...=value
What I need is sth. I could address like:
string name = player["Name"];
string gender = player["Custom"]["Gender"];
string style = player["Custom"]["Style"];
string faceMain = player["Custom"]["Face"]["Main"];
string faceEyes = player["Custom"]["Face"]["Eyes"];
string height = player["Custom"]["Height"];
Or in some way similar to this.
What I tried till now:
Dictionary<string, Hashtable> player = new Dictionary<string, Hashtable>();
player["custom"] = new Hashtable();
player["custom"]["Gender"] = "Female";
player["custom"]["Style"] = "S1";
But the problem starts here (only works with 2 keys):
player["custom"]["Face"] = new Hashtable();
player["Custom"]["Face"]["Main"] = "FM1";
C# is strongly typed so it seems not easy to replicate this exact behavior.
A "possibility" :
public class UglyThing<K,E>
{
private Dictionary<K, UglyThing<K, E>> dicdic = new Dictionary<K, UglyThing<K, E>>();
public UglyThing<K, E> this[K key]
{
get
{
if (!this.dicdic.ContainsKey(key)) { this.dicdic[key] = new UglyThing<K, E>(); }
return this.dicdic[key];
}
set
{
this.dicdic[key] = value;
}
}
public E Value { get; set; }
}
Usage :
var x = new UglyThing<string, int>();
x["a"].Value = 1;
x["b"].Value = 11;
x["a"]["b"].Value = 2;
x["a"]["b"]["c1"].Value = 3;
x["a"]["b"]["c2"].Value = 4;
System.Diagnostics.Debug.WriteLine(x["a"].Value); // 1
System.Diagnostics.Debug.WriteLine(x["b"].Value); // 11
System.Diagnostics.Debug.WriteLine(x["a"]["b"].Value); // 2
System.Diagnostics.Debug.WriteLine(x["a"]["b"]["c1"].Value); // 3
System.Diagnostics.Debug.WriteLine(x["a"]["b"]["c2"].Value); // 4

Got NullReferenceException When I use same code but different expression

I'm writing a project about game's character data.
And each character in the data document have four types, Lv1 and LvMAX, and HP, STR, VIT, INT, MEN.
I use top one code at the middle part and got NullReferenceException when I use it to get some data like:
int x = CD.Parameters.Basic.Awaked.Force.Lv1.STR;
Force will be null. But when I use buttom one at the middle part, Force won't be null.
What's the difference between that two?
Code below
public class ParamType
{
public ParamLv Mebius, Force, Aegis, Magius;
string cost;
DataRow[] Datas;
List<int> ToMebius = new List<int>(), ToForce = new List<int>(), ToAegis = new List<int>(), ToMagius = new List<int>(); //HP, HP, STR, STR, VIT, VIT, INT, INT, MEN, MEN
public ParamType(SData Data, bool awaked)
{
if (awaked)
{
Data.CharaID = CharaCOM.AwakedID(Data.CharaID);
}
Datas = DataCOM.Search(Data.CharaID, Data.DTs.Source, Data.TitleP.Start[(int)DataTitle.CharacterParams], Const.COL_CHARACTER_ID, Const.COL_CHARACTER_ID);
cost = DataCOM.Search(Data.DTs.Source, Data.CharaID, Const.COL_COST, 0, Data.TitleP.Start[(int)DataTitle.CharacterParams], Const.COL_CHARACTER_ID_WITH_TYPE);
List<int>[] SArray = { ToMebius, ToForce, ToAegis, ToMagius };
for (int i = 0; i < Datas.Length; i++)
{
SArray[i] = new List<int>();
for (int j = Const.COL_PARAM_MIN; j < Const.COL_PARAM_MIN + Const.COL_PARAM_LENGTH; j++)
{
SArray[i].Add(Convert.ToInt32(Datas[i][j]));
}
}
/*
this will send NullReference Exception
ParamLv[] PLArray = new ParamLv[4];
for (int i = 0; i < SArray.Length; i++)
{
PLArray[i] = new ParamLv(Data, SArray[i]);
}
*/
/*
This won't get exception and I can get correct data I want.
Mebius = new ParamLv(Data, SArray[0]);
Force = new ParamLv(Data, SArray[1]);
Aegis = new ParamLv(Data, SArray[2]);
Magius = new ParamLv(Data, SArray[3]);
*/
}
public class ParamLv
{
public Params Lv1, LvMax;
List<int> ToLv1 = new List<int>(), ToLvMAX = new List<int>(); //HP, STR, VIT, INT, MEN
public ParamLv(SData Data, List<int> ParamsL)
{
for (int i = 0; i < ParamsL.Count; i += Const.COL_PARAM_MIN_MAX_GAP)
{
ToLv1.Add(ParamsL[i]);
ToLvMAX.Add(ParamsL[i + 1]);
}
Lv1 = new Params(Data, ToLv1);
LvMax = new Params(Data, ToLvMAX);
}
public class Params
{
//some method and properties to get or set Parameters.
}
}
Please tell me if something still bad, and this is my first time to ask question here, so If I did something wrong, please tell me. Thanks for #MicroVirus , #Moriarty and #mvikhona told my mistake.
Mebius = new ParamLv(Data, SArray[0]);
Force = new ParamLv(Data, SArray[1]);
Aegis = new ParamLv(Data, SArray[2]);
Magius = new ParamLv(Data, SArray[3]);
This works, because you are assigning reference to new ParamLv to your properties.
But in this case:
ParamLv[] PLArray = { Mebius, Force, Aegis, Magius };
for (int i = 0; i < PLArray.Length; i++)
{
PLArray[i] = new ParamLv(Data, SArray[i]);
}
you aren't filling your array with variables/properties themselves, but you are filling it with references your properties hold, in the end your array will hold reference to 4 new ParamLw, but your property Force will stay null.
Edit:
I'll try to explain it a bit different. Let's say you have this code:
ParamLv[] PLArray = { Force };
At this moment value of PLArray[0] is same as value of Force, but PLArray[0] isn't Force.
The moment you do this:
PLArray[0] = new ParamLv(Data, null);
new ParamLv(Data, null) returns reference to new ParamLv and you assign this to your PLArray[0], but like I said before PLArray[0] isn't Force, so Force will stay unchanged.
If that didn't explain it well, try to look at this piece of code, it does what you are trying to do.
int a = 1;
int[] myArr = { a }; // a = 1, myArr[0] = 1
myArr[0] = 2; // a = 1, myArr[0] = 2
object obj = null;
object[] objArr = { obj }; // obj = null, objArr[0] = null
objArr[0] = new object(); // obj = null, objArr[0] = 'reference to new object'

Pass multiple parameters to a task

I wish to pass two BlockingCollection<>s to a task. I tried to put them in an object array and pass them but it doesn't work. Can anyone help me with this? The code where i am trying to pass the values is written below:
var lineHolders = new[]
{
new BlockingCollection<string>(linesCapacity),
new BlockingCollection<string>(linesCapacity),
new BlockingCollection<string>(linesCapacity),
new BlockingCollection<string>(linesCapacity)
};
var chunksHolder = new[]
{
new BlockingCollection<List<BsonDocument>>(chunksCapacity),
new BlockingCollection<List<BsonDocument>>(chunksCapacity)
};
for (var processors = 0; processors < 16; processors++)
{
var myLineHolder = lineHolders[processors%lineHolders.Length];
var myChunkHolder = chunksHolder[processors%chunksHolder.Length];
processorTaskArray[processors] = Task.Factory.StartNew((arg) =>
{
var lines = (BlockingCollection<string>) arg[0]; // compiler generates error here
var chunks = (BlockingCollection<List<BsonDocument>>) arg[1]; // compiler generates error here
// perform my work...
},
new object []
{
myLineHolder,
myChunkHolder
});
}
You're using the following overload of StartNew:
public Task StartNew(
Action<Object> action,
Object state
)
Since it's just an object you can't apply indexing on it. Cast it and it will work fine.
for (var processors = 0; processors < 16; processors++)
{
var myLineHolder = lineHolders[processors % lineHolders.Length];
var myChunkHolder = chunksHolder[processors % chunksHolder.Length];
processorTaskArray[processors] = Task.Factory.StartNew((arg) =>
{
var properArg = (object[]) arg;
var lines = (BlockingCollection<string>) properArg[0]; // compiler generates error here
var chunks = (BlockingCollection<List<BsonDocument>>) properArg[1]; // compiler generates error here
// perform my work...
},
new object[]
{
myLineHolder,
myChunkHolder
});
}

Categories