I have a c# class object that is List<int,string> I need to make sure the list's string variable is HtmlEncoded before passing back to an MVC controller (where I will later need to decode) but I'm having difficulty because the company's custom libraries are written in such a way that I have a hard time manipulating the code.
In this particular scenario, the data field is embedded into a SQL statement that is converted to the List<int,string> object. Before this List<int,string> is passed back, I need to use WebUtility.HtmlEncode on the string variable "GroupName":
public List<DatasetModel> GetMembers(List<int> groupIds)
{
using (var work in unitOfWorkFactory())
{
return work.DataContext.Query.Read<DatasetModel>(
$#SELECT {nameof(TableOne.GroupId)
, {(nameof(TableOne.Name))} as GroupName
FROM {this._tableProvider.GlobalTable<TableOne>()}
WHERE {nameof(TableOne.GroupId)} {groupIds.ToSqlInClause()}"
).ToList();
)
}
}
I've tried creating extension methods and something like the following but get type conversion errors, etc, that lead me to write rudimentary for loops and cast() and such that are not appropriate:
List<DatasetModel> returnList = model.Select(x => new DatasetModel{x.GroupId, WebUtility.HtmlEncode(x.Name)}).ToList();
FOLLOW-UP:
Here is what I've had to do to achieve the goal. I don't like it because I am using a foreach loop in the called method. I haven't been able to consistently understand / resolve errors involving 'initializer errors' and List vs generic lists:
public List<DatasetModel> GetMembers(List<int> groupIds)
{
using (var work in unitOfWorkFactory())
{
return EncodeList(work.DataContext.Query.Read<DatasetModel>(
$#SELECT {nameof(TableOne.GroupId)
, {(nameof(TableOne.Name))} as GroupName
FROM {this._tableProvider.GlobalTable<TableOne>()}
WHERE {nameof(TableOne.GroupId)} {groupIds.ToSqlInClause()}"
).ToList();
)
}
}
private static List<DatasetModel> EncodeList(List<DatasetModel> list)
{
var returnList = new List<DatasetModel>();
foreach (var l in list)
{
var m = new DatasetModel(attributeId: l.attributeId, attributeName: WebUtility.HtmlEncode(l.attributeName));
returnList.Add(m);
}
return returnList;
}
Related
Is there any way to return a string parameter and a list to the method in c#?
List<cCountry> countries = new List<cCountry>();
countries = GetCountries(userProfile.Country);
private List<cCountry> GetCountries(string p)
{
inputCollection = new cDTOCollection<cDTOBase>();
outputCollection = new cDTOCollection<cDTOBase>();
outputCollection = UpdateProfileBizobj.ProcessRequest(ActionConstants.ActionGetCountriesList, null);
List<cCountry> countries = new List<cCountry>();
cDTOSingleValue SelectedCountryID = new cDTOSingleValue();
foreach (cDTOCountry countryItem in outputCollection)
{
if (p == countryItem.CountryName)
SelectedCountryID.Id = countryItem.CountryID;
countries.Add(Mapper.Map<cDTOCountry, cCountry>(countryItem));
}
countries.Remove(countries[0]);
return countries;
}
Like in the method above I need to return a parameter
SelectedCountryID and also the countries list.Is there any way to
return both?
populate and return an object instead.
public class ReturnObject
{
public List<cCountry> Countries { get; set; }
public guid SelectedCountryID { get; set; } // don't think you defined what type SelectedCountryID is in your question
}
But if you find yourself needing to return more than 1 thing, it's probably an indication that your method is doing too much and should be refactored.
Why can't you reuse the value that you are sending to the method?
return Tuple.Create(new List<Country>(),"astring")
Answer to your question
You can also use the out modifier on a parameter to pass by reference, which would let the method modify the resulting object, effectively returning it. That's a pretty bad design for most cases though, and you probably refactor your methods into smaller pieces or wrap things up into better objects.
In your code:
private List<cCountry> GetCountries(string p, out cDTOSingleValue SelectedCountryID)
{
//your code
}
Potential Refactoring
Looking at your code it, seems your really are trying to do two separate things.
Getting Countries and mapping them
Finding the last country whose name matches the parameter passed in
So as long as your country list isn't ridiculously large, making two separate method calls will make your code more readable and more maintainable. I like using LINQ to manipulate the in-memory collections.
I'd personally use one method to fetch the data.
private List<cDTOCountry> GetCountries()
{
inputCollection = new cDTOCollection<cDTOBase>();
outputCollection = new cDTOCollection<cDTOBase>();
return UpdateProfileBizobj.ProcessRequest(ActionConstants.ActionGetCountriesList, null);
}
And then later I'd process the data as needed:
var preMappedCountries = GetCountries();
var mappedCountries = preMappedCountries
.Select(c => Mapper.Map<cDTOCountry, cCountry>(c)) //map the data
.Skip(1) //skip the first element (the remove index 0)
.ToList(); //cast to List. Read more on LINQ's deferred execution.
var lastMatchingName = preMappedCountries
.LastOrDefault(c => c.Name == p); //gets the last country with matching name
The benefit to separating the logic into pieces is potential reuse of methods. If you ever find yourself needing to get data without mapping, you can do just that and skip all the LINQ logic. This way the logic that gets data is distinct from the logic that matches country names.
In your case an out param seems more appropriate. Otherwise as Kevin suggested you can return a Tuple.
So I have two collections - one of int?, and one of string.
I want to iterate over both, and I have a good chunk of code that I want to perform to each. However there are some slight differences. if the value is an int?, some additional code is needed.
I'm trying to follow DRY principles, so I don't want to rewrite my code. I also don't want to put it in an external function, as this is already abstracted away from my MVC app controller code and I don't want it getting needlessly complex.
Is there a way to do something like this in c#
foreach(object o in (ints && strings))
{
if(o is int)
{
// do in specific stuff
}
// do all my generic stuff.
}
EDIT:
It's actually int? not int. when I try and combine them into a generic list of type List<object> I get an error
With this particular structure, you can combine them into one big object collection using Concat, like:
foreach (object o in ints.Cast<object>().Concat(strings.Cast<object>()))
But I'd probably suggest breaking out your functionality into a method, and running two loops:
foreach (int i in ints) {
DoSomething(i);
DoSomethingWithInt(i);
}
foreach (string s in strings) {
DoSomething(s);
DoSomethingWithString(s);
}
That will keep things clean and a little more readable in my opinion.
I think it would be cleaner to put the generic stuff in a common function, then loop over both collections. That way you get rid of the somewhat odd if int stuff.
foreach(int number in ints)
{
// do int specific stuff
GeneralFunction(number);
}
foreach(string stringValue in strings)
{
GeneralFunction(number);
}
This could also work for you:
IEnumerator en1 = ints.GetEnumerator();
IEnumerator en2 = strings.GetEnumerator();
while((en1.MoveNext()) && (en2.MoveNext()))
{
WhateverActionWithNullableInt((int?)en1.Current);
WhateverActionWithString((string)en2.Current);
}
Yes, you can do this:
List<int> ints = new List<int>();
List<string> strings = new List<string>();
foreach (object o in ints.Cast<object>().Concat(strings))
{
if (o is int)
{
// do in specific stuff
}
// do all my generic stuff.
}
I would separate it into functions and take advantage of overloading myself, but you said you didn't want to do that.
You should create a new list, which is the concatenation of the two lists :
EDIT
List<object> list = new List<object>();
List<int> ints = new List<int>(); ints.Add(74); ints.Add(47);
List<string> strings = new List<string>(); strings.Add("hello"); strings.Add("hello2");
list.AddRange(ints.Cast<object>());
list.AddRange(strings.Cast<object>());
foreach (object o in list)
{
Trace.WriteLine(o);
if (o is int)
{
// do in specific stuff
}
// do all my generic stuff.
}
I currently working on an dynamic upload module. The idea is to only define the file and the data contract for each new file. Currently I'm using reflection with 2 foreach, this is some heavy code to do this. As you can see in the code I have my object containing the csv file and 2 other lists. These two lists contains all the properties of the object where I would like to do data validation on.
var myCustomObjects = CsvSettings(new CsvReader(readFile, config)).GetRecords<MyCustomObject>();
var decimalProprties = GetPropertyNames<MyCustomObject>(typeof(decimal)).ToList();
var dateProprties = GetPropertyNames<MyCustomObject>(typeof(DateTime)).ToList();
foreach (var myCustomObject in myCustomObjects)
{
foreach (var dateProperty in dateProprties)
{
var value = myCustomObject.GetType().GetProperty(dateProperty).GetValue(myCustomObject, null);
Console.WriteLine(value); //code to check and report the value
}
Console.WriteLine(myCustomObject.Een + "|" + myCustomObject.Twee + "|" + myCustomObject.Drie);
}
How can I do this with an expression or even another way to have so less heavy code?
The code seems fine as-is. You could perhaps simplify it a little by using a method that returns Key/Value pairs for all public properties of a certain type, like so (error handling elided for brevity):
public static IEnumerable<KeyValuePair<string, T>> PropertiesOfType<T>(object myObject)
{
var properties =
from property in myObject.GetType().GetProperties()
where property.PropertyType == typeof(T) && property.CanRead
select new KeyValuePair<string, T>(property.Name, (T)property.GetValue(myObject));
return properties;
}
Then you can avoid the additional call to GetProperty() in your inner loop:
foreach (var myCustomObject in myCustomObjects)
{
foreach (var dateProperty in PropertiesOfType<DateTime>(myCustomObject))
{
Console.WriteLine(dateProperty.Value); // code to check and report the value.
}
}
Also note that you don't seem to need the .ToList() calls.
I'm using EF 4.1 and I'm trying to enumerate a company list for a grid. I have two options in the current project: select all companies from the DbContext (Entities) and load them into an object from a non-anonymous type (let's say EmpresaGrid) or select all companies into anonymous type objects with the same structure like Empresa (which is the entity I'm selecting from).
The first option (creating a model class for that) would require a little more work, but can be, eventually, more readable. Still, I'm not sure about that. The second option is what I'm using right now.
So, first question: it's better to create a model class only for displaying data or use anonymous type? Doing a direct select is out of question: a SELECT * is too big and that might make everything damn slow (I guess). So selection into another type creates a custom query with only the needed fields.
Using the second option (anonymous type), I have this code (simplified version):
public static IEnumerable<object> Grid()
{
Entities db = new Entities();
var empresas = db.Empresas
.Select(e => new
{
Cgc = e.Cgc, // PK
(...)
Address = new
{
AddressLine = e.EnderecoSede.AddressLine,
(...)
}
},
Contato = e.Contato,
(...)
})
.ToList();
return empresas;
}
The anonymous type I'm creating has around 40 lines of code, so it's kinda big, but it recreates part of the Empresa class struct (since the grid is waiting for a Empresa object). Anyway, I have a problem with the data format. For example, I would like to format the Cgc property using a custom string format. I have a public method for this, FormataCgc. This method receives a string and returns it formatted using some internal conditions.
So, my problem is how to that. For example, I have tried this:
var empresas = db.Empresas
.Select(e => new
{
Cgc = FormataCgc(e.Cgc),
}
But that doesn't work because FormataCgc cannot be translated into SQL (and I don't want to convert it). I also tried this:
var empresas = db.Empresas
.Select(e => new
{
(...)
}
.ToList();
foreach (var e in empresas) {
e.Cgc = FormataCgc(e.Cgc);
}
But it cannot be done since anonymous types have only read-only properties.
So, my second question is: how exactly can I do that? I need to change the data after selecting it, but using anonymous types? I've done a little research, and the best thing I've found was this: Calling a custom method in LINQ query. In that solution, Ladislav suggested doing a second select from the IEnumerable, but since the grid is excepting Empresa I cannot do that (I need to change or add properties, not encapsulate them).
I'm not sure if I was clear enough, but feel free to ask any questions. Also, the grid I'm currently using is a Telerik ASP.NET MVC Grid, which receives a IEnumerable (where T is a class) as model data and them iterates each object, doing its magic.
Since you're already converting this into an IEnumerable<T>, you can do the custom formatting as you stream the results in the client. Do your db.Select, and then convert to the appropriate format afterwards, ie:
var empresas = db.Empresas
.Select(e => new
{
(...)
})
.ToList();
foreach (var e in empresas) {
yield return new {
Cgc = FormataCgc(e.Cgc),
// Copy other properties here, as needed...
};
}
That being said, I'd personally recommend making a custom class, and not return an anonymous type. Your conversion would then be:
foreach (var e in empresas) {
yield return new YourClass(FormataCgc(e.Cgc), ...); // Construct as needed
}
This will dramatically improve the usability of this method, as you will have proper, named access to your properties from the caller of the method.
I think the solution to both of your questions is to create a model class. Sure it is a little bit more work up front, but it will allow you greater flexibility in the long run. Your custom model class can then handle the formatting for you.
public class EmpresaGridModel
{
public string Cgc { get; set; }
public string CgcFormatted
{
return FormataCgc(this.Cgc);
}
//properties for the other fields will have to be created as well obviously
}
Your telerik grid can then bind directly to the CgcFormatted property
Is it possible to itterate directly over properties of the objects stored within a Dictionary collection in C#?
For example, I have a Dictionary called Fields of type Dictionary<String, Field>. The Field object has a property of Data which is of type XmlDataDocument so I would like to do something like,
foreach(XmlDataDocument fieldData in Fields.Values.Data){
}
I know it's pretty trivial since all I would need to do when itterating over Field objects instead would be,
XmlDataDocument fieldData = field.Data;
within the Field itteration however if there is a quicker way to do it I'd like to know :-)
In C# 3.0:
foreach (var data in Fields.Values.Select(x => x.Data))
{
}
It's not any "quicker" though.
yes, create a custom collection based on Dictionary and then add your own iterator to it...
public class MyFieldCollection: Dictionary<string, Field>
{
public IEnumerable<XmlDataDocument> Data
{
foreach(Field f in this.Values)
yield return f.Data;
}
}
Then in client code all you need to do is
MyFieldCollection MFC = new MyFieldCollection();
foreach (XmlDataDocument doc in MFC.Data)
{
// DoWhatever (doc );
}