Refactoring similar methods using generics parameter in c# and linq - c#

I have two methods they are exactly the same except the first parameter.I don't want to repeat the duplicate code. I was wondering how can we refactor the following code using generic parameters.
First method
private Dictionary<List<string>, List<string>> GetFinancialLtmDataSet(List<sp_get_company_balance_sheet_amount_ltm_Result> itemResult, int neededyear)
{
var requestedData =
itemResult.OrderByDescending(x => x.date.Year).Take(neededyear).Select(x => new { date = x.date.Date });
var addFields = new List<string>();
var dataSet = new Dictionary<List<string>, List<string>>();
int counter = 0;
foreach (var itemy in requestedData)
{
var skipvalue = itemResult.Skip(counter);
var columns = skipvalue.OrderBy(x => itemy.date).ToList();
var cc = columns.First();
counter++;
var properties =
cc.GetType()
.GetProperties()
.Select(x => new { Name = x.Name, Value = x.SetMethod, a = x.GetValue(cc, null) })
.ToList();
foreach (var property in properties)
{
addFields.Add(property.Name);
if (property.a != null)
{
dataSet.Add(new List<string> { property.Name }, new List<string> { property.a.ToString() });
}
}
}
return dataSet;
}
Second method
private Dictionary<List<string>, List<string>> GetFinancialQuartelyDataSet(List<sp_get_company_balance_sheet_amount_quaterly_Result> itemResult, int neededyear)
{
var requestedData =
itemResult.OrderByDescending(x => x.date.Year).Take(neededyear).Select(x => new { date = x.date.Date });
var addFields = new List<string>();
var dataSet = new Dictionary<List<string>, List<string>>();
int counter = 0;
foreach (var itemy in requestedData)
{
var skipvalue = itemResult.Skip(counter);
var columns = skipvalue.OrderBy(x => itemy.date).ToList();
var cc = columns.First();
counter++;
var properties =
cc.GetType()
.GetProperties()
.Select(x => new { Name = x.Name, Value = x.SetMethod, a = x.GetValue(cc, null) })
.ToList();
foreach (var property in properties)
{
addFields.Add(property.Name);
if (property.a != null)
{
dataSet.Add(new List<string> { property.Name }, new List<string> { property.a.ToString() });
}
}
}
return dataSet;
}
I have created a following method to make it generic but not been able to get the final implementation any suggestion appreciated.
private List<T> GetFinancialReport<T>(List<T> data, int neededyear)
{
//what should I return from here
return data;
}
and would like to use the above method like this
var balancesheetResult=balancesheet.ToList();
var testData = GetFinancialReport<BalanceSheet_sp>(balancesheetResult, 5);
var cashflowresult=cashflow.ToList();
var testData1 = GetFinancialReport<CahsFlow_sp>(cashflowresult, 10);

From what is shown above the objects (at least the properties involved) match. So you could code against an interface here:
private Dictionary<List<string>, List<string>> GetFinancialReport(List<IBalance>, int neededyear)
{
...
}

Related

Subscribe to an Mqtt broker and write into OPC server using windows Forms Application

I'm trying to subscribe to an MQTT broker and write into an OPC server using windows forms application. But I have some problems I get always an exception "Object reference not set to an instance of an object." everything is good but when i arrived to write into an opc server avec subscribing and getting the mqtt message i got an exception. Below is the code This a method in the WCF service.
public void StartTransferFromMQTTtoOPC()
{
try
{
// Check if at least one transfer if configured
string jmsg;
while (TransferHelper.SubscribedBlockingCollection.TryTake(out jmsg))
{
// Check if any transfer is configured.
if (ExportedMQTTTransfers == null || ExportedMQTTTransfers.archList == null ||
ExportedMQTTTransfers.archList.Count == 0)
return;
// check which Mqtt Transfer is responsible for that topic
var message = JsonConvert.DeserializeObject<TopicStruct>(jmsg);
var mqqtmessage = message.Message;
var transfer = ExportedMQTTTransfers.archList.Find(x => x.Topic == message.TopicName);
// get Group Information and server information from the topic
//OPCGroup grp = transfer.OPCgrpsPerServer.TryGetValue()
//Load Configuration of specific topic Fields Mapping
Dictionary<string, string> fieldsmapping;
var first = transfer.OPCgrpsPerServer.First();
OPCGroup grp = first.Value[0];
fieldsmapping = grp.FieldsMapping;
StringBuilder payloadTransformer = new StringBuilder("{\"Iterator\": {\"#loop($.ListofValues)\": {");
foreach (KeyValuePair<string, string> entry in fieldsmapping)
{
payloadTransformer.Append($"\"{entry.Value}\":\"#currentvalueatpath($.{entry.Key})\",");
}
payloadTransformer.Length--;
payloadTransformer.Append("}}}");
string resPayload = JUST.JsonTransformer.Transform(payloadTransformer.ToString(), mqqtmessage);
var myItems = JsonConvert.DeserializeObject<ConsumedItem>(resPayload);
if (myItems is null)
{
return;
}
MappedTags = new Dictionary<string, Dictionary<string, string>>();
List<int> lstItemHandles = new List<int>();
//Read From a CSV file and put data in a Dictionary
string csvFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "TagMappings.csv");
var rows = File.ReadAllLines(csvFile);
var totalcols = rows[0].Split(',').Length;
Dictionary<string, string> Y = new Dictionary<string, string>();
string columns = "", csvCell = "";
string[] column;
List<string> MQTTList = new List<string>();
List<string> csvList = new List<string>();
// List<string> GroupNameList = new List<string>();
foreach (var words in rows)
{
columns = words;
column = columns.Split(new[] { ',' }, StringSplitOptions.None);
for (int i = 0; i < column.Length; i++)
{
//if (columns.Split(',')[0].Equals("GroupName"))
//{
// csvCell = columns.Split(',')[i];
// Console.WriteLine(csvCell);
// GroupNameList.Add(csvCell);
//}
if (columns.Split(',')[0].Equals("OPCTag"))
{
csvCell = columns.Split(',')[i];
csvList.Add(csvCell);
}
if (columns.Split(',')[0].Equals("MQTTTag"))
{
csvCell = columns.Split(',')[i];
MQTTList.Add(csvCell);
}
}
Y = csvList.Zip(MQTTList, (k, v) => new { Key = k, Value = v }).ToDictionary(x => x.Value, x => x.Key);
MQTTServiceLogger.TraceLog(MessageType.Control, " Reading CSV file Successfully.");
}
//test Nadia
transfer.Name = "Group0";
MappedTags.Add(grp.GroupName, Y);
// check if retrieved item exist in current group
Dictionary<string, string> tagsmapped = new Dictionary<string, string>();
MappedTags.TryGetValue(transfer.Name, out tagsmapped);
List<OPCItemTransfer> ToBeWriteItems = new List<OPCItemTransfer>();
List<int> Handles = new List<int>();
List<object> Values = new List<object>();
List<string> Items = new List<string>();
foreach (var item in myItems.Iterator)
{
string itemname;
if (tagsmapped.ContainsKey(item.ItemID))
{
//override List of items
tagsmapped.TryGetValue(item.ItemID, out itemname);
item.ItemID = itemname;
ToBeWriteItems.Add(item);
//Items.Add(item.ItemValue);
MQTTServiceLogger.TraceLog(MessageType.Control, "Tags Mapping succeeded .");
}
}
if (ToBeWriteItems.Count == 0)
{
return;
}
OPCItemTransfer item1 = new OPCItemTransfer();
for (int i = 0; i < grp.listItems.Count; i++)
{
lstItemHandles.Add(grp.listItems[i].serverItemHandle);
item1 = ToBeWriteItems.Find(x => x.ItemID == grp.listItems[i].ItemID);
Values.Add(item1.ItemValue);
MQTTServiceLogger.TraceLog(MessageType.Control, "Getting items values Successfully.");
}
if (Values.Count > 0)
{
//2.write to OPC
switch (grp.grpWriteMode)
{
#region Synchronous write
case WriteModes.Synchronous:
{
int[] arrErr;
WriteSynch(grp.ServerIndex,
grp.GroupIndex, lstItemHandles.ToArray(),
Values.ToArray(), out arrErr);
break;
}
#endregion
#region Asynchronous write
case WriteModes.Asynchronous:
{
int cancelID;
int[] arrErr;
int transactionID = 0;
WriteAsynch(grp.ServerIndex, grp.GroupIndex, lstItemHandles.ToArray(),
Values.ToArray(), transactionID, out cancelID, out arrErr);
break;
}
#endregion
#region Synchronous write IO2
case WriteModes.SynchronousIO2:
{
int[] arrErr;
WriteSynch2(grp.ServerIndex,
grp.GroupIndex, lstItemHandles.ToArray(),
Values.ToArray(), out arrErr);
break;
}
#endregion
#region Asynchronous write IO3
case WriteModes.AsynchronousIO3:
{
int cancelID;
int[] arrErr;
int transactionID = 0;
WriteAsynch3(grp.ServerIndex, grp.GroupIndex, lstItemHandles.ToArray(),
Values.ToArray(), transactionID, out cancelID, out arrErr);
break;
}
#endregion
}
}
MQTTServiceLogger.TraceLog(MessageType.Error, "Error while trying to write in an OPC Server.");
}
}
catch (Exception Ex0)
{
//throw;
}
}

Looking way to refactor these two methods into single method

Hi All i am trying to generate the word document with two different tables included in it, for this purpose i have two similar methods where i am passing word document reference and data object and table to the similar methods..
Now i am looking to make single method in generic way so that in different places i can use single method by passing parameters to it
Method 1 :
private static List<OpenXmlElement> RenderExhaustEquipmentTableDataAndNotes(MainDocumentPart mainDocumentPart, List<ProjectObject<ExhaustEquipment>> exhaustEquipment,Table table)
{
HtmlConverter noteConverter = new HtmlConverter(mainDocumentPart);
var equipmentExhaustTypes = new Dictionary<string, List<ProjectObject<ExhaustEquipment>>>();
foreach (var item in exhaustEquipment)
{
string exhaustEquipmentName = item.TargetObject.Name;
if (!equipmentExhaustTypes.ContainsKey(exhaustEquipmentName))
{
equipmentExhaustTypes.Add(exhaustEquipmentName, new List<ProjectObject<ExhaustEquipment>>());
}
equipmentExhaustTypes[exhaustEquipmentName].Add(item);
}
List<OpenXmlElement> notes = new List<OpenXmlElement>();
int noteIndex = 1;
foreach (var exhaustEquipmentItem in equipmentExhaustTypes)
{
List<string> noteIndices = new List<string>();
for (int exhaustEquipmentConditionIndex = 0; exhaustEquipmentConditionIndex < exhaustEquipmentItem.Value.Count; exhaustEquipmentConditionIndex++)
{
var condition = exhaustEquipmentItem.Value[exhaustEquipmentConditionIndex];
var row = new TableRow();
Run superscriptRun = new Run(new RunProperties(new VerticalTextAlignment { Val = VerticalPositionValues.Superscript }));
if (exhaustEquipmentConditionIndex == 0)
{
row.Append(RenderOpenXmlElementContentCell(new Paragraph(
new List<Run> {
new Run(new RunProperties(), new Text(exhaustEquipmentItem.Key) { Space = SpaceProcessingModeValues.Preserve }),
superscriptRun
}), 1,
new OpenXmlElement[] {new VerticalMerge { Val = MergedCellValues.Restart },new TableCellMargin {
LeftMargin = new LeftMargin { Width = "120" },
TopMargin = new TopMargin { Width = "80" } }
}));
}
else
{
row.Append(RenderTextContentCell(null, 1, null, null, new OpenXmlElement[] { new VerticalMerge { Val = MergedCellValues.Continue } }));
}
row.Append(RenderTextContentCell(condition.TargetObject.IsConstantVolume ? "Yes" : "No"));
row.Append(RenderTextContentCell($"{condition.TargetObject.MinAirflow:R2}"));
row.Append(RenderTextContentCell($"{condition.TargetObject.MaxAirflow:R2}"));
if (condition.TargetObject.NotesHTML?.Count > 0)
{
foreach (var note in condition.TargetObject.NotesHTML)
{
var compositeElements = noteConverter.Parse(note);
var htmlRuns = compositeElements.First().ChildElements.Where(c => c is Run).Cast<Run>().Select(n => n.CloneNode(true));
notes.Add(new Run(htmlRuns));
noteIndices.Add(noteIndex++.ToString(CultureInfo.InvariantCulture));
}
}
if (exhaustEquipmentConditionIndex == exhaustEquipmentItem.Value.Count - 1 && condition.TargetObject.NotesHTML?.Count > 0)
{
superscriptRun.Append(new Text($"({String.Join(',', noteIndices)})") { Space = SpaceProcessingModeValues.Preserve });
}
table.Append(row);
}
}
List<OpenXmlElement> notesSection = new List<OpenXmlElement>();
List<OpenXmlElement> result = RenderNotesArray(table, notes, notesSection);
return result;
}
and I am calling this method like this in below
var table = new Table(RenderTableProperties());
table.Append(new TableRow(
RenderTableHeaderCell("Name"),
RenderTableHeaderCell("Constant Volume"),
RenderTableHeaderCell("Minimum Airflow", units: "(cfm)"),
RenderTableHeaderCell("Wet Bulb Temperature", units: "(cfm)")
));
body.Append(RenderExhaustEquipmentTableDataAndNotes(mainDocumentPart, designHubProject.ExhaustEquipment, table));
Method 2:
private static List<OpenXmlElement> RenderInfiltrationTableData(MainDocumentPart mainDocumentPart, List<ProjectObject<Infiltration>> infiltration,Table table)
{
HtmlConverter noteConverter = new HtmlConverter(mainDocumentPart);
var nameByInflitrationObject = new Dictionary<string, List<ProjectObject<Infiltration>>>();
foreach (var infiltrationData in infiltration)
{
string infiltrationName = infiltrationData.TargetObject.Name;
if (!nameByInflitrationObject.ContainsKey(infiltrationName))
{
nameByInflitrationObject.Add(infiltrationName, new List<ProjectObject<Infiltration>>());
}
nameByInflitrationObject[infiltrationName].Add(infiltrationData);
}
List<OpenXmlElement> notes = new List<OpenXmlElement>();
int noteIndex = 1;
foreach (var inflitrationDataItem in nameByInflitrationObject)
{
List<string> noteIndices = new List<string>();
for (int inflitrationNameIndex = 0; inflitrationNameIndex < inflitrationDataItem.Value.Count; inflitrationNameIndex++)
{
var dataItem = inflitrationDataItem.Value[inflitrationNameIndex];
var row = new TableRow();
Run superscriptRun = new Run(new RunProperties(new VerticalTextAlignment { Val = VerticalPositionValues.Superscript }));
if (inflitrationNameIndex == 0)
{
row.Append(RenderOpenXmlElementContentCell(new Paragraph(
new List<Run> {
new Run(new RunProperties(), new Text(inflitrationDataItem.Key) { Space = SpaceProcessingModeValues.Preserve }),superscriptRun
}), 1,
new OpenXmlElement[] {new VerticalMerge { Val = MergedCellValues.Restart },new TableCellMargin {
LeftMargin = new LeftMargin { Width = "120" },
TopMargin = new TopMargin { Width = "80" }}
}));
}
else
{
row.Append(RenderTextContentCell(null, 1, null, null, new OpenXmlElement[] { new VerticalMerge { Val = MergedCellValues.Continue } }));
}
row.Append(RenderTextContentCell($"{dataItem.TargetObject.AirflowScalar.ToString("R2", CultureInfo.CurrentCulture)} cfm {EnumUtils.StringValueOfEnum(dataItem.TargetObject.InfiltrationCalculationType).ToLower(CultureInfo.CurrentCulture)}"));
if (dataItem.TargetObject.NotesHTML?.Count > 0)
{
foreach (var note in dataItem.TargetObject.NotesHTML)
{
var compositeElements = noteConverter.Parse(note);
var htmlRuns = compositeElements.First().ChildElements.Where(c => c is Run).Cast<Run>().Select(n => n.CloneNode(true));
notes.Add(new Run(htmlRuns));
noteIndices.Add(noteIndex++.ToString(CultureInfo.InvariantCulture));
}
}
if (inflitrationNameIndex == inflitrationDataItem.Value.Count - 1 && dataItem.TargetObject.NotesHTML?.Count > 0)
{
superscriptRun.Append(new Text($"({String.Join(',', noteIndices)})") { Space = SpaceProcessingModeValues.Preserve });
}
table.Append(row);
}
}
List<OpenXmlElement> notesSection = new List<OpenXmlElement>();
List<OpenXmlElement> result = RenderNotesArray(table, notes, notesSection);
return result;
}
and then i am calling this method here like as below
var table = new Table(RenderTableProperties());
table.Append(new TableRow(
RenderTableHeaderCell("Type"),
RenderTableHeaderCell("Air Flow")
));
body.Append(RenderInfiltrationTableData(mainDocumentPart, designHubProject.Infiltration, table));
i know these are lots of lines but is there any generic way to use single method out of these two similar methods and i am using .net core
Could any one please suggest any idea or suggestion how can i refactor these two methods into single method that would be very grateful.
many thanks in advance
Before we can create a single function that handles both types, achieving the highly laudable goal of removing gratuitous duplication, we should clean the code up to make it easier to see which parts, if any, are different between the two nearly identical methods. And there is a lot to clean up, even if we only had one function.
In short, your functions are too long, having too much much code in one place, and in fact too much code altogether.
In the following, the original code has been broken down into multiple functions with specific purposes and refactored to remove DIY nonsense in favor of the standard library functions and the removal of pointless code.
static IEnumerable<OpenXmlElement> RenderExhaustEquipmentTableDataAndNotes(MainDocumentPart mainDocumentPart, List<ProjectObject<ExhaustEquipment>> exhaustEquipment, Table table)
{
var equipmentByType = exhaustEquipment.ToLookup(item => item.TargetObject.Name);
List<OpenXmlElement> notes = new List<OpenXmlElement>();
foreach (var items in equipmentByType)
{
Run superscriptRun = CreateSuperScriptRun();
foreach (var item in items)
{
var row = new TableRow();
if (item == items.First())
{
row.Append(CreateFirstRowStartingCell(items.Key, superscriptRun));
}
else
{
row.Append(RenderTextContentCell(null, 1, null, null, new[] {
new VerticalMerge { Val = MergedCellValues.Continue }
}));
}
row.Append(RenderTextContentCell(item.TargetObject.IsConstantVolume ? "Yes" : "No"));
row.Append(RenderTextContentCell($"{item.TargetObject.MinAirflow:R2}"));
row.Append(RenderTextContentCell($"{item.TargetObject.MaxAirflow:R2}"));
table.Append(row);
var itemNotes = ParseNotes(mainDocumentPart, item.TargetObject.NotesHTML);
if (item == items.Last() && itemNotes.Any())
{
UpdateSuperScript(superscriptRun, itemNotes);
}
notes.AddRange(itemNotes);
}
}
List<OpenXmlElement> result = RenderNotesArray(table, notes, new List<OpenXmlElement>());
return result;
}
private static Run CreateSuperScriptRun()
{
return new Run(new RunProperties(new VerticalTextAlignment
{
Val = VerticalPositionValues.Superscript
}));
}
private static void UpdateSuperScript(Run superscriptRun, IEnumerable<OpenXmlElement> notes)
{
superscriptRun.Append(new Text($"({string.Join(",", Enumerable.Range(0, notes.Count()))})")
{
Space = SpaceProcessingModeValues.Preserve
});
}
private static IEnumerable<OpenXmlElement> ParseNotes(MainDocumentPart mainDocumentPart, IEnumerable<OpenXmlElement> notes)
{
return notes == null
? Enumerable.Empty<OpenXmlElement>()
: notes.Select(note => new HtmlConverter(mainDocumentPart).Parse(note))
.Select(note => note.First().ChildElements
.OfType<Run>()
.Select(n => n.CloneNode(true))).Select(htmlRuns => new Run(htmlRuns))
.ToList();
}
private OpenXmlElement CreateFirstRowStartingCell(string key, Run superscriptRun)
{
return RenderOpenXmlElementContentCell(
new Paragraph(new List<Run> {
new Run(new RunProperties(), new Text(key) { Space = SpaceProcessingModeValues.Preserve }),
superscriptRun
}),
1,
new OpenXmlElement[] {
new VerticalMerge { Val = MergedCellValues.Restart },
new TableCellMargin { LeftMargin = new LeftMargin { Width = "120" }, TopMargin = new TopMargin { Width = "80" } }
});
}
Now, let's tackle the second function:
static IEnunumerable<OpenXmlElement> RenderInfiltrationTableData(MainDocumentPart mainDocumentPart, IEnunumerable<ProjectObject<Infiltration>> infiltration, Table table)
{
var infiltrationsByType = infiltration.ToLookup(item => item.TargetObject.Name);
List<OpenXmlElement> notes = new List<OpenXmlElement>();
foreach (var inflitrations in infiltrationsByType)
{
Run superscriptRun = CreateSuperScriptRun();
foreach (var item in inflitrations)
{
var row = new TableRow();
if (item == inflitrations.First())
{
row.Append(CreateFirstRowStartingCell(inflitrations.Key, superscriptRun));
}
else
{
row.Append(RenderTextContentCell(null, 1, null, null, new[] {
new VerticalMerge { Val = MergedCellValues.Continue }
}));
}
row.Append(RenderTextContentCell($"{item.TargetObject.AirflowScalar:R2} cfm {item.TargetObject.InfiltrationCalculationType}").ToLower());
table.Append(row);
var itemNotes = ParseNotes(mainDocumentPart, item.TargetObject.NotesHTML);
if (item == inflitrations.Last() && itemNotes.Any())
{
UpdateSuperScript(superscriptRun, itemNotes);
}
notes.AddRange(itemNotes);
}
}
IEnumerable<OpenXmlElement> result = RenderNotesArray(table, notes, new List<OpenXmlElement>());
return result;
}
As we have seen, duplication can be massively reduced simply by extracting code into simple helper functions.
This also makes it far easier to see just where the differences are between the two functions.
It is simply a matter of
row.Append(RenderTextContentCell(item.TargetObject.IsConstantVolume ? "Yes" : "No"));
row.Append(RenderTextContentCell($"{item.TargetObject.MinAirflow:R2}"));
row.Append(RenderTextContentCell($"{item.TargetObject.MaxAirflow:R2}"));
vs.
row.Append(RenderTextContentCell($"{item.TargetObject.AirflowScalar:R2} cfm {item.TargetObject.InfiltrationCalculationType}").ToLower());
To achieve your desired goal of a single function, we can make a generic function, and require that the caller pass in a function that will take care of these differences.
static IEnumerable<OpenXmlElement> RenderTableDataAndNotes<T>(
MainDocumentPart mainDocumentPart,
IEnumerable<ProjectObject<T>> projects,
Table table,
Func<ProjectObject<T>, IEnumerable<OpenXmlElement>> createCells
) where T : ITargetObject
{
var projectsByType = projects.ToLookup(item => item.TargetObject.Name);
List<OpenXmlElement> notes = new List<OpenXmlElement>();
foreach (var items in projectsByType)
{
Run superscriptRun = CreateSuperScriptRun();
foreach (var item in items)
{
var row = new TableRow();
if (item == items.First())
{
row.Append(CreateFirstRowStartingCell(items.Key, superscriptRun));
}
else
{
row.Append(RenderTextContentCell(null, 1, null, null, new[] {
new VerticalMerge { Val = MergedCellValues.Continue }
}));
}
var itemCells = createCells(item);
foreach (var cell in itemCells)
{
row.Append(cell);
}
table.Append(row);
var itemNotes = ParseNotes(mainDocumentPart, item.TargetObject.NotesHTML);
if (item == items.Last() && itemNotes.Any())
{
UpdateSuperScript(superscriptRun, itemNotes);
}
notes.AddRange(itemNotes);
}
}
IEnumerable<OpenXmlElement> result = RenderNotesArray(table, notes, new List<OpenXmlElement>());
return result;
}
Now, when we call it for say some Exhaust Equipment, we do so as follows:
var rendered = RenderTableDataAndNotes(mainDocumentPart, exhaustProjects, table,
exhaust => new[] {
RenderTextContentCell(exhaust.TargetObject.IsConstantVolume ? "Yes" : "No"),
RenderTextContentCell($"{exhaust.TargetObject.MinAirflow:R2}"),
RenderTextContentCell($"{exhaust.TargetObject.MaxAirflow:R2}"),
});
And for infiltration projects, we would do as follows:
var rendered = RenderTableDataAndNotes(
mainDocumentPart,
infiltrationProjects,
table,
infiltration => new[] {
RenderTextContentCell($"{item.TargetObject.AirflowScalar:R2} cfm {item.TargetObject.InfiltrationCalculationType}")
.ToLower()
});
The code could still be substantially improved even now. Currently it requires that the various project types implement a common ITargetObject interface declaring the Name property used to group projects by type. If you refactored your code to reduce nesting by hoisting Name to the ProjectObject<T> type, then we could remove the constraint and the otherwise useless requirement that Infiltration and ExhaustEquipment implement the ITargetObject interface.
Note, if you can't change the types, you can adjust the code in a few ways.
For example, you can remove the type constraint on T and build the lookup outside and pass it to the function:
static IEnumerable<OpenXmlElement> RenderTableDataAndNotes<T>(
MainDocumentPart mainDocumentPart,
ILookup<string, ProjectObject<T>> projectsByType,
Table table,
Func<ProjectObject<T>, IEnumerable<OpenXmlElement>> createCells
)
Then you would call it as
var infiltrationProjectsByType = infiltrationProjects.ToLookup(project => project.Name);
var rendered = RenderTableDataAndNotes(
mainDocumentPart,
infiltrationProjectsByType,
table,
infiltration => new[] {
RenderTextContentCell($"{infiltration.TargetObject.AirflowScalar:R2} cfm {infiltration.TargetObject.InfiltrationCalculationType}").ToLower()
}
);

How to apply order by to linq query?

In c# linq, I have this code which works
private IQueryable<v_CompanyInquiryInfo> SearchCompany(string pCompanyName)
{
var mCompany = from d in db.v_CompanyInquiryInfo
where d.CompanyName.ToLower().Equals(pCompanyName)
select ((v_CompanyInquiryInfo)d);
return mCompany;
}
And I have this
private IQueryable SearchCompanies(string pValues)
{
string mValues = pValues;
foreach (string lWord in iRestrictedWords)
{
mValues.Replace(lWord, "");
}
var mSearchArray = pValues.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var mCompanyCriteria = db.v_CompanyInquiryInfo.AsExpandable().Where(TradingInquiryController.CompanyContainsSearchTerms(mSearchArray));
var mCompanies = mCompanyCriteria
.Select(x => new
{
x.CompanyName,
x.CompanyID,
x.SearchTags,
Rank = mSearchArray.Sum(s => ((x.SearchTags.Length - x.SearchTags.Replace(s, "").Length) / s.Length))
});
var mResults = mCompanies.OrderByDescending(o => o.Rank).Skip(0).Take(20);
return mResults;
}
which also works. However I want the return type of this second function to be IQueryable<v_CompanyInquiryInfo>. The problem is there is a Rank new dynamic column added, and then I sort by it. How can I apply the same ordering but without creating a new column for it, then apply a cast to v_CompanyInquiryInfo. So that I can return IQueryable<v_CompanyInquiryInfo>. I can't figure out the syntax for this. Also it can return all columns.
Thanks
You don't need to create that property:
private IQueryable SearchCompanies(string pValues)
{
string mValues = pValues;
foreach (string lWord in iRestrictedWords)
{
mValues.Replace(lWord, "");
}
var mSearchArray = pValues.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var mCompanyCriteria = db.v_CompanyInquiryInfo.AsExpandable().Where(TradingInquiryController.CompanyContainsSearchTerms(mSearchArray));
var mCompanies = mCompanyCriteria
.OrderByDescending(x => mSearchArray.Sum(s => ((x.SearchTags.Length - x.SearchTags.Replace(s, "").Length) / s.Length))
;
//var mResults = mCompanies.Skip(0).Take(20);
return mCompanies;
}

How to assign "var" inside if statement

I need to do this:
var productsLocation = response.blah blah; //with linq query
var item; // even var item = null; //not valid
if(condition){
item = productsLocation.linq query
} else {
item = productsLocation.differentquery
}
var group = item.query;
Is this possible? If yes, how?
EDIT: here is my exact code:
var productLocation = response.productLocation.Select(p => ProductLocationStaticClass.DtoToModel(p));
var items;
if (condition)
{
items = productLocation.Select(s => new ProductClass(s)).Where(s => categories.Contains(s.CategoryName));
} else {
items = productLocation.Select(s => new ProductClass(s)).Where(s => categories.Contains(s.CategoryName) && stocks.Contains(s.Barcode));
}
If you look closely at the logic, you notice you don't actually even need the if block. The whole thing can be written in one expression as follows:
var items = productLocation
.Select(s => new ProductClass(s))
.Where(s => categories.Contains(s.CategoryName) && (condition || stocks.Contains(s.Barcode)));
First of all get your response variable type, then initialize 'item' variable as IEnumarable where T is same as response variable type
var productsLocation = response.productLocation.Select(p => ProductLocationStaticClass.DtoToModel(p));
IEnumerable<ProductClass> item;
if (condition)
{
items = productLocation.Select(s => new ProductClass(s)).Where(s => categories.Contains(s.CategoryName));
}
else
{
items = productLocation.Select(s => new ProductClass(s)).Where(s => categories.Contains(s.CategoryName) && stocks.Contains(s.Barcode));
}
var group = item.Where(condition);
You can do it with IEnumerable interface in this way:
using System.Collections;
using System.Collections.Generic;
List<string> products = new List<string>() { "First", "Second", "Third", "Fourth" };
IEnumerable item;
var condition = false;
if (condition)
{
item = products.Select(x=>x);
}
else
{
item = products.Where(x => x.StartsWith("F"));
}
var group = item.Cast<string>().Where(/*...Here your conditions...*/)

How to replace normal foreach to linq ForEach?

public static List<TDuplicate> ValidateColumnInList<TItem, TDuplicate>(List<TDuplicate> DuplicateExpression) where TDuplicate : DuplicateExpression
{
List<TDuplicate> TempDuplicateExpression = new List<TDuplicate>();
var itemProperties = typeof(TItem).GetProperties();
foreach (var DplExpression in DuplicateExpression)
{
bool IsContainColumn = itemProperties.Any(column => column.Name == DplExpression.ExpressionName);
if (!IsContainColumn)
{
TempDuplicateExpression.Add(DplExpression);
}
}
return TempDuplicateExpression;
}
In the above section how to replace above foreach to linq ForEach.
You do not need foreach or ForEach here. Below code should give you result:
var itemProperties = typeof(TItem).GetProperties();
List<TDuplicate> tempDuplicateExpression = DuplicateExpression
.Where(m => !itemProperties.Any(column => column.Name == m.ExpressionName))
.ToList();
return tempDuplicateExpression;
You can get result by this simple way:
var result = DuplicateExpression.Where(n=>!itemProperties.Any(column => column.Name == n.ExpressionName)).ToList();
Or you can user ForEach like this:
DuplicateExpression.ForEach(n=>
{
bool IsContainColumn = itemProperties.Any(column => column.Name == n.ExpressionName);
if (!IsContainColumn)
{
TempDuplicateExpression.Add(n);
}
}
)

Categories