I just downloaded the SortableBindingList and I'm trying to assign it to this LINQ query (instead of var):
var q = from r in document.Descendants("release")
select new
{
Release = r.Attribute("id").Value,
Artist = String.Join(";", r.Element("artists").Descendants("artist").Select(x => x.Element("name").Value).ToArray()),
Album = r.Element("title").Value
};
It's probably not that hard, but I'm just really confused about how to do this...
Some help will be appreciated!
EDIT
Static class:
public static class LINQExtension
{
public static SortableBindingList<object> ToSbl(this IEnumerable<object> items)
{
return new SortableBindingList<object>(items);
}
}
Assignment:
SortableBindingList<object> sbl = LINQExtension.ToSbl(q);
releases_dataGridView.DataSource = sbl;
Because you're using an anonymous type, you need to create it using type inference:
public static SortableBindingList<T> ToSbl(this IEnumerable<T> items) {
return new SortableBindingList<T>(items);
}
var sbl = (...).ToSbl();
Related
I need to return multiple items from a function. How can I do that?
public List<string> GetInfo()
{
var result = new List<string>();
return result;
}
How can I return something like this? Basically List of string and maybe also a list of generic type.
public List<string> GetInfo()
{
var result = new List<string>();
return result and someType;
}
public class someType
{
public List<SomeOthertype> someOthertype { get; set; }
}
If I understand you right, you can try using named tuples:
public (List<string> result, List<SomeOthertype> other) GetInfo()
{
var result = new List<string>();
someType instance = new someType();
//TODO: put relevant code here
// we return both result and someOthertype in one tuple
return (result, instance.someOthertype);
}
Usage:
var info = GetInfo();
var result = info.result;
var other = info.other;
I would propose to use a generic method to be possible use different types:
public static (List<string>, List<U>) GetInfo<U>()
{
var list = new List<string>();
var another = new List<U>();
//...
return (list, another);
}
From c# 7 onward there are tuple value types that are the cleanest way to return multiple values from the function.
Pre c# 7 you can use out parameters
I am wondering whether this method can be done better. I need to filter a Generic list on a member name which is passed in as string. My thinking was to convert the generic list to a dynamic list and then cast the expandoObject to a Dictionary and check for the existence of the member name. Finally, convert the dynamic list back to generic list by using JsonSerializer. What are your ideas for a better implementation? Reflection? Dynamic LINQ (Scott Guthrie did some work back in 2008)? Expression Trees?
public static IEnumerable<T> FilterListByStringPropertyName<T>(this IEnumerable<T> genericList, int? enumId, string enumFieldName)
{
if (string.IsNullOrEmpty(enumFieldName))
{
throw new NullReferenceException("FilterByEnum: enumFieldName cannot be empty");
}
if (enumId == null)
{
//skip method as no filtering needed
return genericList;
}
if (genericList.Count() == 0)
{
return genericList;
}
List<T> #return = new List<T>();
List<dynamic> dynamicList = new List<dynamic>();
//fill the dynamic list from generic list
foreach (var genericItem in genericList)
dynamicList.Add(genericItem.ToDynamic());
var first = dynamicList.FirstOrDefault();
//initialise filteredDynamicList
IEnumerable<dynamic> filteredDynamicList = dynamicList;
if (enumId != null)
{
//ExpandoObject implements IDictionary<string, object>, so cast as that to check what the fields are
if (!((IDictionary<string, object>)first).ContainsKey(enumFieldName))
{
throw new KeyNotFoundException(string.Format("{0} is not a member of {1}", enumFieldName, genericList.GetType().GetGenericArguments()[0]));
}
//filter by the AddressStatus enum (as int)
filteredDynamicList = dynamicList.Where(a => (int)((IDictionary<string, object>)a)[enumFieldName] == enumId.Value);
}
//convert from dynamic back to to generic
var json = Newtonsoft.Json.JsonConvert.SerializeObject(filteredDynamicList);
#return = Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>>(json);
return #return;
}
First try to see if you can find a strongly typed solution(Expression/Func) then try other methods (Reflection)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace ConsoleApplication9
{
class Program
{
static void Main(string[] args)
{
var customers = Enumerable.Range(1, 10).Select(c => new Customer() { Id = c, Name = "Customer " + c });
var filteredCustomers = StronglyNameFilter(customers, c => c.Id == 1);
var filteredCustomers2 = StronglyNameFilter(customers, c => c.Name == "Customer 1");
var filteredCustomers3 = ReflectionFilter(customers, "Id", 1);
var filteredCustomers4 = ReflectionFilter(customers, "Name", "Customer 1");
Console.ReadLine();
}
private static IEnumerable<T> StronglyNameFilter<T>(IEnumerable<T> collection, Func<T, bool> filter)
{
return collection.Where(filter).ToList();
}
private static IEnumerable<T> ReflectionFilter<T>(IEnumerable<T> collection, string property, object value)
{
if (collection.Count() == 0)
return new List<T>();
PropertyInfo pInfo = collection.First().GetType().GetProperty(property);
return collection.Where(c => object.Equals(pInfo.GetValue(c), value)).ToList();
}
}
public class Customer
{
public string Name { get; set; }
public int Id { get; set; }
}
}
I don't know who resolve this segment code with variance:
I have an abstract father class:
public abstract class PdfObject
{...}
And two child classes:
public class PdfText : PdfObject
{...}
public class PdfImage : PdfObject
{...}
Now, my wrong or empiric code is the next:
public IList<PdfText> GetTexts()
{
List<PdfText> result = new List<PdfText>();
List<PdfObject> list = GetList();
foreach(var item in list)
{
if(item is PdfText) result.Add(item)
}
return result;
}
public List<PdfObject> GetList()
{...}
Well, i read a lot of this theme, but don't stand how use variance in generics or use a better solution for this issue.
Please, help me and thanks.
This doesn't have much to do with variance, directly. Your problem is here:
public IList<PdfText> GetTexts()
{
List<PdfText> result = new List<PdfText>();
List<PdfObject> list = GetList();
foreach(var item in list)
{
if(item is PdfText) result.Add(item)
}
return result;
}
The static type of the item variable is PdfObject so you cannot add it to result; you need to cast it. For example
if (item is PdfText) result.Add((PdfText)item);
This is inefficient because you check the type twice: once for the is operator and once for the cast. Instead, you're supposed to do this:
public IList<PdfText> GetTexts()
{
List<PdfText> result = new List<PdfText>();
List<PdfObject> list = GetList();
foreach(var item in list)
{
var textItem = item as PdfText
if (textItem != null) result.Add(textItem)
}
return result;
}
Or, you can use linq:
var result = GetList().OfType<PdfText>().ToList();
You could do this...
public IList<PdfText> GetTexts()
{
List<PdfText> result = GetList()
.Where(x => x is PdfText)
.Select(x => (PdfText)x)
.ToList();
return result;
}
Edited: This works, but OfType is better.
You could have a better solution in this situation.
public class ClientOfPdfObject<T> where T: PdfObject
{
public List<T> GetItems()
{
List<PdfObject> list = GetList();
var result = new List<T>();
foreach (var pdfObject in list)
{
if (typeof (T) == pdfObject.GetType())
result.Add((T) pdfObject);
}
return result;
}
//Get PdfObjects somewhere (ex. Db)
private List<PdfObject> GetList()
{
var list = new List<PdfObject>
{
new PdfImage(),
new PdfImage(),
new PdfImage(),
new PdfText(),
new PdfText(),
new PdfText(),
new PdfText()
};
return list;
}
}
static void main()
{
var text = new ClientOfPdfObject<PdfText>();
//contains 4 itmes (PdfText)
var pdfTexts = text.GetItems();
var image = new ClientOfPdfObject<PdfImage>();
//contains 3 items (PdfImage)
var pdfImages = image.GetItems();
}
Tomorrow, when you add more pdf objects (ex. PdfGraph), you don't need to change anything.
I am trying to find a generic way to assign values to a property dictated by a lambda expression, look at the example code below, how would the signature for the ConverToEntities method look and how would it be called?
static void Main()
{
List<long> ids = new List<long> {1, 2, 3};
//Non generic way
List<Data> dataItems = ids.ConvertToDataItems();
//Generic attempt!!
List<Data> differntDataItems =
ids.ConvertToEntities<Data>( p => p.DataId );
}
public class Data
{
public long DataId;
public string Name;
}
public static class ExtensionMethods
{
public static List<Data> ConvertToDataItems(this List<long> dataIds)
{
return dataIds.Select(p => new Data { DataId = p }).ToList();
}
public static List<T> ConvertToEntities<TProp>(
this List<long> entities, Func<TProp> lambdaProperty )
{
return entities.Select(p => new T {lambdaProperty} ).ToList();
}
}
Ok. The closest I could get was this :
class Program
{
static void Main(string[] args)
{
List<long> ids = new List<long> { 1, 2, 3 };
//Non generic way
List<Data> dataItems = ids.ConvertToDataItems();
//Generic attempt!!
Func<long, Data> selector = (p => new Data { DataId = p });
List<Data> differntDataItems = ids.ConvertToEntities<Data>(selector);
}
}
public class Data
{
public long DataId;
public string Name;
}
public static class ExtensionMethods
{
public static List<Data> ConvertToDataItems(this List<long> dataIds)
{
return dataIds.Select(p => new Data { DataId = p }).ToList();
}
public static List<TProp> ConvertToEntities<TProp>(this List<long> entities, Func<long, TProp> selector)
{
return entities.Select(selector).ToList();
}
}
This works.
I have the feeling you got urself a little confused with what you actually want as the return type. It would be cool to be able to specify what we want in the method call or smth. For example:
public static List<TProp> ConvertToEntities<T, TProp>(List<T> entities, Func<T, TProp> selector)
{
return entities.Select(selector).ToList();
}
This provides us more flexibility on the return type. But since we are doing this using extensions, I assume this is impractical because we need to know what type we are extending:
this List<long> entities,
Nice question.
EDIT Code suggestion fix.
You can do something like this, but it's not as simple or nice. The lambda p => p.DataId gives you the get accessor of the property. You could use Expressions to get the setter, but it's probably better to use the setter directly in the lambda:
List<Data> differntDataItems =
ids.ConvertToEntities<long, Data>((p, i) => p.DataId = i);
The implementation would look like this:
public static List<T> ConvertToEntities<TProp, T>(
this List<TProp> dataIds, Action<T, TProp> lambdaProperty)
where T : new()
{
return dataIds.Select(
p =>
{
var result = new T();
lambdaProperty(result, p);
return result;
}).ToList();
}
I believe #Zortkun is right about the return type. Try the followin:
public static List<TProp> ConvertToEntities<TProp>(
this List<long> entities, Func<long, TProp> lambdaProperty )
{
return entities.Select(lambdaProperty).ToList();
}
and you would call it as follows:
ids.ConvertToEntities<Data>( p => new Data { DataId = p } );
From Parameter to Property?
public class ConcatenateListTMember
{
public static void Test()
{
var someList = new List<AnyClass>();
someList.Add(new AnyClass("value1"));
someList.Add(new AnyClass("value2"));
Console.WriteLine(Concatenate(someList, "SomeProperty"));
Console.ReadLine();
}
static string Concatenate<T>(List<T> list, string specifiedPropertyOfT)
{
string output = String.Empty;
// TODO: Somehow concatenate all the specified property elements in the list?
return output;
}
}
internal class AnyClass
{
public AnyClass(string someProperty)
{
SomeProperty = someProperty;
}
public string SomeProperty { get; set; }
}
How might it be possible to implement the generic method in this code sample?
Please note that specifiedPropertyOfT does not have to be a string if the same aim can be achieved using another type.
Ideally, reflection would not be needed :)
I think you're looking for the new overloads of string.Join in .NET 4 which would allow:
IEnumerable<AnyClass> sequence = ...;
string joined = string.Join(",", sequence.Select(x => x.SomeProperty));
If you can't use a lambda expression to express the property - e.g. because this has to be done at execution time - then you will have to use reflection.
Note that the selector in Select doesn't have to return strings - String.Join will call ToString on any non-string values.
Even better - an extension method:
static string Concatenate<T>(this IEnumerable<T> list, Func<T,string> func)
{
return String.Join("",list.Select(func));
}
Usage:
someList.Concatenate(i => i.SomeProperty);
Live example: http://rextester.com/runcode?code=LRA78268
Try something like this. I've created an extension method on IEnumerable:
public static class Extension
{
public static string ConcatinateString<T>(this IEnumerable<T> collection, Func<T, string> GetValue)
{
StringBuilder sb = new StringBuilder();
foreach (var item in collection)
{
sb.Append(GetValue(item));
}
return sb.ToString();
}
}
Then so call it, you would use something like this:
var values = new List<TestClass>
{
new TestClass(){Name="John",Comment="Hello"},
new TestClass(){Name="Smith", Comment="Word"}
};
string s = values.ConcatinateString((x => x.Name));
string v = values.ConcatinateString((x => x.Comment));
In this example s = "JohnSmith" and v = "HelloWord". The Func() gives you flexibility. You are basically telling the function where to go to get the string to concatenate. I also used a StringBuilder in case you are working with long collections.