I want to develop a Generic Extension Method which should arrange the string in alphabetical then by lengthwise ascending order.
I mean
string[] names = { "Jon", "Marc", "Joel",
"Thomas", "Copsey","Konrad","Andrew","Brian","Bill"};
var query = names.OrderBy(a => a.Length).ThenBy(a => a);
What is the way to develop Generic Extension Method?
I tried :
public static class ExtensionOperation
{
public static T[] AlphaLengthWise<T>(this T[] names)
{
var query = names.OrderBy(a => a.Length).ThenBy(a => a);
return query;
}
}
I received :
Error 1: T does not contain definition for Length
Error 2: can not convert System.Linq.IOrderedEnumerable to T[].
The first error is because Length is a property of the String class while in your generic version the type of the T parameter is not known. It could be any type.
The second error is because you return just the query object but not the actual result. You might need to call ToArray() before returning.
With little modifications you could come up with this:
public static class ExtensionOperation
{
public static IEnumerable<T> AlphaLengthWise<T, L>(
this IEnumerable<T> names, Func<T, L> lengthProvider)
{
return names
.OrderBy(a => lengthProvider(a))
.ThenBy(a => a);
}
}
Which you could use like this:
string[] names = { "Jon", "Marc", "Joel", "Thomas", "Copsey", "Konrad", "Andrew", "Brian", "Bill" };
var result = names.AlphaLengthWise(a => a.Length);
Why do you want to do this generically? Just use
public static class ExtensionOperations
{
public static IEnumerable<string> AlphaLengthWise(this string[] names)
{
var query = names.OrderBy(a => a.Length).ThenBy(a => a);
return query;
}
}
I think you may be a little confused to the purpose of generics.
Generics are a way to tailor a class or method to a specific type. A generic method or class is designed to work for any type. This is most easily illustrated in the List<T> class, where it can be tailored to be a list of any type. This gives you the type-safety of knowing the list only contains that specific type.
Your problem is designed to work on a specific type, the string type. Generics are not going to solve a problem which involves a specific type.
What you want is a simple (non-generic) Extension Method:
public static class ExtensionOperations
{
public static IEnumerable<string> AlphaLengthWise(
this IEnumerable<string> names)
{
if(names == null)
throw new ArgumentNullException("names");
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
}
Making the argument and the return type IEnumerable<string> makes this a non-generic extension method which can apply to any type implementing IEnumerable<string>. This will include string[], List<string>, ICollection<string>, IQueryable<string> and many more.
I want to develop a Generic Extension Method which should arrange the strings in alphabetical then ...
public static class ExtensionOperation
{
public static IEnumerable<String> AplhaLengthWise(
this IEnumerable<String> names)
{
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
}
Copy how Microsoft does it:
public static class ExtensionOperation {
// Handles anything queryable.
public static IOrderedQueryable<string> AlphaLengthWise(this IQueryable<string> names) {
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
// Fallback method for non-queryable collections.
public static IOrderedEnumerable<string> AlphaLengthWise(this IEnumerable<string> names) {
return names.OrderBy(a => a.Length).ThenBy(a => a);
}
}
You want to use IEnumerable<T> instead of T[]. Other than that, you won't be able to use Length of T, since not all types has a Length property. You could modify your extension method to .OrderBy(a => a.ToString().Length)
If you know you'll always be dealing with strings, use IEnumerable<String> rather than IEnumerable<T>, and you'll be able to access the Length property immediately.
Related
I want to create a function that would search a list for something and return bool.
MyList has multiple elements inside. Each has a variable name assigned different string. I want to search the list for a particular name.
Example:
public class Type
{
public string name;
}
List<Type> MyList;
bool FindByName(string str)
{
foreach (Type type in MyList)
{
if (type.name == str)
return true;
}
}
The FindByName function is what I would like to make universal. A function that would take:
List<T>, NameOfVariableToLookIn, U WhatToLookFor
And you could just give the function:
List<Type>, name, string str
Worried if this is even possible. I really don't want to write a new function for each new list I create.
You could use the Any() extension method from System.Linq namespace. And you could implement an extension method. For sample:
public static class Extensions
{
public static bool FindByName(this IEnumerable<Type> list, string str)
{
return list.Any(x => x.name == str);
}
}
Remember, an extension method is a static method instead and not part of the list so you should reference Extensions class. You could use it like this:
List<Type> MyList = new List<Type>();
MyList.Add(..); // add objects
var exists = MyList.FindByName("john");
Right now my code looks like this:
var ids = projectId.HasValue ? new List<Guid> { projectId.Value } : new List<Guid>();
Is there a more succinct way of creating a list in one line of code, with one element added optionally?
Another idea for an extension method (the name could definitely be improved, maybe PossiblyCreateSingletonList?):
public static class NullableExtensions
{
public static List<T> SingletonList<T>(this Nullable<T> item) where T : struct
{
return item.HasValue ? new List<T> { item.Value } : new List<T>();
}
}
Usage:
Guid? projectId = null;
List<Guid> projectIds = projectId.SingletonList(); // empty list
I would solve this using a extension method like this:
public static void AddIfNotNull<T>(this List<T> list, T? value) where T : struct
{
if(value != null)
{
list.Add(value.Value);
}
}
Than it could be used like this:
var ids = new List<Guid>();
ids.AddIfNotNull(projectId);
Maybe not as "crafty" (and not a one-liner) as your proposal, but in my opinion it is much easier to read and understand. If desired to be used as a one-liner you could modify the return type of the extension to be the list. That would make it possible to be used something like var ids = new List<Guid>().AddIfNotNull(projectId);
This probably isn't a good idea, but in C# 6, collection initializers also work when Add() is an extension method.
This means you can write the extension Add() like this:
public static void Add<T>(this List<T> list, T? item) where T : struct
{
if (item.HasValue)
{
list.Add(item.Value);
}
}
And then this code will do what you want:
var list = new List<Guid> { projectId };
Note that this will only work for value types (because of the T/T? distinction) and there is no simple way to make it work for reference types.
Also, I would find the line above very surprising, being more succinct is not always better. Which is why I actually wouldn't use this code.
That's pretty succinct, but another option would be to use LINQ:
var ids = new[] { projectId }.Where(x => x.HasValue).Select(x => x.Value).ToList();
If you're going the extension method route, it would have to look something like:
public static void AddIfNotNull<T>(this List<T> list, T? value)
where T : struct
{
if (value.HasValue)
{
list.Add(value.Value);
}
}
You'd have to build a second extension method for reference types (where T : class) if you needed.
I've got a method that computes a list. At certain points in the algorithm a single element from the list needs to be chosen. It doesn't really matter which element is chosen, but I'd like to leave it up to the user to decide.
Right now, I've added an extension method IList<T>.Random() which simply takes a random element. .First() would have worked equally as well. Supposing I want to let the user pick which method is used, or perhaps an entirely different method, how would that look?
I was thinking about using an enum with limited options, and then I could wrap each of these calls in a switch and call the appropriate function. But maybe some sort of lambda function would be more appropriate?
This method needs to be used in two different places, once on a List<char> and once on a List<string>. I want to use the same method for both.
This isn't a GUI app. I'm trying to decide how to design the API.
Specifically, I want to have a field like
public Func<IList<T>, T> SelectElement = list => list.First();
Which would then be used in the method,
public string Reverse(string pattern, IList<object> args = null, IDictionary<string, object> kwargs = null)
But generic fields aren't possible. So I'm looking for an alternative solution. One would be to make the SelectElement method an argument to Reverse(), then I could make it generic... but I was hoping to keep it at a class-level for re-usability. Don't want to pass any more args to the function if I can help it.
Edit: full source code
how about this:
public class MyClass
{
public static class C<T>
{
public static Func<IList<T>, T> SelectElement;
}
public int Test(IList<int> list)
{
return C<int>.SelectElement(list);
}
}
static class Program
{
static void Main(string[] args)
{
MyClass.C<char>.SelectElement = xs => xs.First();
MyClass.C<int>.SelectElement = xs => xs.First();
var list = new List<int>(new int[] { 1, 2, 3 });
var c = new MyClass();
var v = c.Test(list);
Console.WriteLine(v);
}
}
Here's an extremely basic example I put together using a generic method that takes in a Func<IEnumerable<T>, T> for selecting an item from the list and then returns the result. I've done a few examples of how to call it:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
//Simple list.
var list = new List<int> { 1, 2, 3, 4 };
// Try it with first
var result = DoItemSelect(list, Enumerable.First);
Console.WriteLine(result);
// Try it with last
result = DoItemSelect(list, Enumerable.Last);
Console.WriteLine(result);
// Try it with ElementAt for the second item (index 1) in the list.
result = DoItemSelect(list, enumerable => enumerable.ElementAt(1));
Console.WriteLine(result);
}
public static T DoItemSelect<T>(IEnumerable<T> enumerable, Func<IEnumerable<T>, T> selector)
{
// You can do whatever you method does here, selector is the user specified func for
// how to select from the enumerable. Here I just return the result of selector directly.
return selector(enumerable);
}
}
}
If you want to limit the choices a user has you could follow the route of an enum and make this method a private method and then have a way to convert the enum to the appropriate selector delegate to pass to the underlying private method.
public Func<IList<object>, object> SelectElement = list => list.First();
private T _S<T>(IEnumerable<T> list)
{
return (T)SelectElement(list.Cast<object>().ToList());
}
I can make the anonymous method work on objects, thereby avoiding generics, and then add a helper method which is what I'll actually use to call it. A little ugly, but seems to work.
This works for chars and strings. Haven't tested with other types. Built this before I saw Ralph's code, which is practically the same.
LINQPad code:
void Main()
{
var chars = new List<char>();
var strings = new List<string>();
chars.AddRange(new char[] {'1','2','4','7','8','3'});
strings.AddRange(new string[] {"01","02","09","12","28","52"});
chars.Dump();
strings.Dump();
Func<IList<object>, string> SelectFirst = ( list )
=> list.First().ToString();
Func<IList<object>, string> SelectLast = ( list )
=> list.Last().ToString();
Func<IList<object>, string> SelectRandom = ( list )
=> list.ElementAt( new Random().Next(0, list.Count())).ToString();
SelectBy(SelectFirst, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectFirst, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectLast, chars.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, strings.Cast<object>().ToList()).Dump();
SelectBy(SelectRandom, chars.Cast<object>().ToList()).Dump();
}
private string SelectBy(Func<IList<object>, string> func, IList<object> list)
{
return func(list);
}
I would like to create a function that will return list of type that is specified by me at run time.
I tried something along this line:
public static List<T> GetMyList<T>(string[] itemList)
{
List<T> resultList = new List<T>(itemList.Length);
return resultList.AddRange(itemList);
}
But this doesn't work. Obviously I don't fully understand how to pass a type to be converted to.
Any help would be appreciated it.
Edit:
It looks like that it is not possible, but here is more info. String array will contain numbers and I would like to convert those numbers sometimes into int, sometimes into short.
Idea behind is to have a generic function that will attempt to convert items into whatever type list I tell it.
You need to provide a method to convert a string into a T - you can do this using a Func<string, T>:
public static List<T> GetMyList<T>(string[] itemList, Func<string, T> conversionFunc)
{
return itemList.Select(conversionFunc).ToList();
}
e.g.
List<int> ints = GetMyList(new[] { "1", "2", "3" }, s => int.Parse(s));
A slightly more elegant solution would be to add an extension method to string that automatically calls the parser for type T, like so:
public static class GenericParser {
public static T Parse<T>(this string input) {
var converter = TypeDescriptor.GetConverter(typeof(T));
if ( converter != null ) {
return ( T )converter.ConvertFromString(input);
}
return default(T);
}
}
Then, your conversion function would look something like:
public static List<T> GetMyList<T>(string[] itemList) {
List<T> list = new List<T>();
list.AddRange(Array.ConvertAll<string, T>(itemList, delegate(string s) {
return s.Parse<T>();
}));
return list;
}
And the usage would be:
List<int> integers = GetMyList<int>(new []{"1", "2", "3", "4"});
List<double> doubles = GetMyList<double>(new []{"1.0", "2.0", "3.0", "4.0"});
and so on.
My first thought is that this won't work because not every object type can be constructed from a string. Perhaps you want something with a signature more like:
public static List<T> GetMyList<T>(T[] itemList)
{
List resultList = new List(itemList.Length);
foreach (t in itemList)
{
resultList.add(t);
}
return resultList;
}
(forgive my syntax. I don't have a compiler handy right now to check it.)
this doesn't work because system has no idea how to convert string to generic T. Also even if it is known, it will not work, because C# (prior to 4) doesn't have type covariance. So use either foreach to copy and convert elements one by one or use Select from Linq
Similar to Lee's but more generic...
public static class Tools
{
public static List<TResult> ToList<T, TResult>(
this IEnumerable<T> input,
Func<T, TResult> conversion)
{
return input.Select(conversion).ToList();
}
public static List<TResult> ToList<T, TResult>(
this IEnumerable<T> input,
Func<T, int, TResult> conversion)
{
return input.Select(conversion).ToList();
}
}
class Program
{
static void Main(string[] args)
{
var input = new[] { "1", "2", "3" };
var ret = input.ToList(i => int.Parse(i));
// 1,2,3
var ret2 = input.ToList((i,j) => int.Parse(i) + j * 10);
// 1,12,23
}
}
I have asked this question about using the a Linq method that returns one object (First, Min, Max, etc) from of a generic collection.
I now want to be able to use linq's Except() method and I am not sure how to do it. Perhaps the answer is just in front on me but think I need help.
I have a generic method that fills in missing dates for a corresponding descriptive field. This method is declared as below:
public IEnumerable<T> FillInMissingDates<T>(IEnumerable<T> collection, string datePropertyName, string descriptionPropertyName)
{
Type type = typeof(T);
PropertyInfo dateProperty = type.GetProperty(datePropertyName);
PropertyInfo descriptionProperty = type.GetProperty(descriptionPropertyName);
...
}
What I want to accomplish is this. datePropertyName is the name of the date property I will use to fill in my date gaps (adding default object instances for the dates not already present in the collection). If I were dealing with a non-generic class, I would do something like this:
foreach (string description in descriptions)
{
var missingDates = allDates.Except(originalData.Where(d => d.Description == desc).Select(d => d.TransactionDate).ToList());
...
}
But how can I do the same using the generic method FillInMissingDates with the dateProperty and descriptionProperty properties resolved in runtime?
I think the best way would be to define an interface with all of the properties that you want to use in your method. Have the classes that the method may be used in implement this interface. Then, use a generic method and constrain the generic type to derive from the interface.
This example may not do exactly what you want -- it fills in missing dates for items in the list matching a description, but hopefully it will give you the basic idea.
public interface ITransactable
{
string Description { get; }
DateTime? TransactionDate { get; }
}
public class CompletedTransaction : ITransactable
{
...
}
// note conversion to extension method
public static void FillInMissingDates<T>( this IEnumerable<T> collection,
string match,
DateTime defaultDate )
where T : ITransactable
{
foreach (var trans in collection.Where( t => t.Description = match ))
{
if (!trans.TransactionDate.HasValue)
{
trans.TransactionDate = defaultDate;
}
}
}
You'll need to Cast your enumeration to ITransactable before invoking (at least until C# 4.0 comes out).
var list = new List<CompletedTransaction>();
list.Cast<ITransactable>()
.FillInMissingDates("description",DateTime.MinValue);
Alternatively, you could investigate using Dynamic LINQ from the VS2008 Samples collection. This would allow you to specify the name of a property if it's not consistent between classes. You'd probably still need to use reflection to set the property, however.
You could try this approach:
public IEnumerable<T> FillInMissingDates<T>(IEnumerable<T> collection,
Func<T, DateTime> dateProperty, Func<T, string> descriptionProperty, string desc)
{
return collection.Except(collection
.Where(d => descriptionProperty(d) == desc))
.Select(d => dateProperty(d));
}
This allows you to do things like:
someCollection.FillInMissingDates(o => o.CreatedDate, o => o.Description, "matching");
Note that you don't necessarily need the Except() call, and just have:
.. Where(d => descriptionProperty(d) != desc)
foreach (string description in descriptions)
{
var missingDates = allDates.Except<YourClass>(originalData.Where(d => d.Description == desc).Select(d => d.TransactionDate).ToList());
}
In fact, almost all LINQ extension in C# have a generic possible value. (Except and Except)
If you're going to identify the property to be accessed by a string name, then you don't need to use generics. Their only purpose is static type safety. Just use reflection to access the property, and make the method work on a non-generic IEnumerable.
Getting Except result with multiple properties working with custom data class is not allowed.
You have to use it like this: (given in msdn 101 LINQ Samples)
public void Linq53()
{
List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();
var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];
var productOnlyFirstChars = productFirstChars.Except(customerFirstChars);
Console.WriteLine("First letters from Product names, but not from Customer names:");
foreach (var ch in productOnlyFirstChars)
{
Console.WriteLine(ch);
}
}
Having the key, you can handle your data accordingly :)