A single generic solution? - c#

I want to write a generic method along the following lines:
public IEnumerable<T> S<T> (List<T> source)
{
//dosomething with source
if (someCondition)
yield return null;
else
yield return someNonNullItem;
}
T can be a value type (e.g. int), a nullable type (e.g. int?), or a ref type (e.g. string). In all the three cases, I want to have the ability to return a null value.
The //dosomething block is pretty generic, involves shifting things around, and can be used with all types with no modification. Similarly, the (someCondition) boolean check does not have any type dependency.
Some considerations:
I cannot use default(T) where T is a non-nullable value type (e.g. default(T) where T is int won't work). An explicit representation of null is required.
I don't want to convert from T to T? if I can avoid it since the source list can be quite long (millions of items).
At present, I'm stuck with having to write three functions, and one of them has to have a different name (because the type constraints are not deemed part of the method signature). The three functions have identical bodies (not shown for brevity).
public IEnumerable<T?> S<T>(List <T> source) where T:struct
{
}
public IEnumerable<T?> S<T>(List <T?> source) where T : struct
{
}
public IEnumerable<T> S4Ref<T>(List <T> source) where T : class
{
}
In the first two methods, I need the T:struct constraint to be able to return the Nullable. In the third method: (a) I need a new name, S4Ref, to avoid clashing with the first method, and, (b) I need the T:class constraint to be able to return a null.
In reality, there are numerous such S methods I have to write, and if I follow the above approach, I'll have to write three versions for each of them. I'll also turn them into extension methods for List
Questions:
Is there a way to have a single generic function that does this? Or at least reduce from 3 to 2 methods?
If not, what is the best way to eliminate duplication in the function bodies?
At present I'm veering towards using T4 templates to address this.

You've set yourself up with conflicting constraints. In the problem definition, you say you want a function that works on value types (i.e. int) but be able to return null without turning it into a nullable type. As a design paradigm, I don't expect a collection of things to include something that doesn't exist. Yeah, I said that. To me, returning a null item means it doesn't exist, and yet you are returning null. If the purpose of function S is to filter items, it would be better to skip the item that doesn't match and return the next one.
For example, a typical use of IEnumerable is code that looks like this:
List<int> myList = .... // somehow fill the list
foreach(int element in S(myList))
{
// do something with the int element. What should I expect to do with a null
// even if you could return one? The only thing I could reasonable do here is
// skip it. I have no idea which element of myList the null corresponds to
}
in other words, even if the foreach look like this:
foreach(int? element in S(myList))
I'm still stuck as to what to do with a null value for element. There is still no context to know which element of myList caused a null from function S.

Related

Is there a way to chain multiple "is" statements in c# to check whether an instance is in a collection of class types?

if(item is classA || item is classB || item is classC || ...)
is there a way to write that line of code more elegantly? I think this can be done but how do you create a collection of types (not instances) so that you can check whether the type of item is inside of that collection?
With C# 9 you can do this:
if (item is classA or classB or classC) {}
See https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#pattern-matching-enhancements for more info.
To create a collection of types, use typeof():
new[] { typeof(Class1), typeof(Class2), typeof(Class3) }
This creates a Type[]. However, is can't be used on Type instances. You can use IsAssignableFrom instead. Note that just comparing if the type of item is equal to the array elements is not enough to replicate the behaviour of is - is does more than that. It checks the inheritance hierarchy, and a bunch of other stuff too.
Combine that with Any, you get:
if (new[] { typeof(Class1), typeof(Class2), typeof(Class3) }.Any(x => item.GetType().IsAssignableFrom(x))) {
}
This certainly doesn't look too much more elegant than your original, but if you have a lot of types to check, it will eventually be shorter.
Note that unless all the types have some common members, checking whether an object is any of those types isn't very useful. There isn't anything extra that you suddenly can now do, once you know that item is one of these types. You still can't safely cast it to a specific type.
If all the types do have some common members, consider writing an interface with all the common members, and making those types implement that interface. This way you just need to check if item is that interface!
I'm not sure it is more elegant, but if you want to check whether the item's type is part of a collection you could do
if (new [] { typeof(classA), typeof(classB), typeof(classC) }.Contains(item.GetType()))
{
}
Following the comments, to replicate the is behaviour, you could do
if (new[] { typeof(classA), typeof(classB), typeof(classC) }.Any(x => item.GetType().IsAssignableFrom(x)))
{
}

Would you consider changing the interface or using an adapter here?

I have an interface that returns an Enumerable of a type.
public interface IMapper
{
IEnumerable<IContract> Get(params object[] objects);
}
That basically takes one or more parameters whose type is also unknown and returns an Enumerable of any type that implements IContract. Feel free to suggest an alternative for this.
Now this looks simple enough and works. However, here's a scenario where it always returns one object (of type IContract). I can't change the fact that it returns only one object.
var escalationMapper = _factory.GetEscalationMapper();
//we only get one object with a list of triggers but the interface returns a list. Change the interface?
var escalations = escalationMapper.Get(trackingGroupCode);
_factory.Release(escalationMapper);
var contracts = escalations as IList<IContract> ?? escalations.ToList();
response = Request.CreateResponse(!contracts.Any()
? HttpStatusCode.NotFound : HttpStatusCode.OK, contract);
The line of code we're interested is what follows the comment because I don't feel comfortable returning just one object and calling it a list. There are other usages of the Get() method that returns lists proper This just happened to return at most 1 object..
Is it reasonable to return a single object as a list, or is there a better way to implement this?
Like I said in the comments, there is nothing wrong design-wise with your code. Even if the particular place where you call Get is guaranteed to return at most a single item within the returned list, that doesn't mean it's going to be guaranteed everywhere else that calls IMapper.Get.
If you really want to simplify it so that it returns the single object instead of a one-length list, though, I wouldn't recommend changing the interface to have an additional method, either. This would break all classes that implement IMapper and force you to implement that new method, even in places where the new method wouldn't add anything useful. This would be an especially big problem if anyone else uses your code for their own purposes, as it would force them to perform the rewrite as well.
One thing you could do to get around that issue, however, is to instead declare the new method as an extension method:
public static class IMapperExtensions
{
public static IContract GetSingle(this IMapper mapper, params object[] objects)
{
return mapper.Get(objects).FirstOrDefault();
}
}
Then you can call it like so:
var escalation = escalationMapper.GetSingle(trackingGroupCode);
This will give you the functionality you need without breaking any existing implementations of your interface.
I agree with #Abion47 and #chrylis comments - 0 or 1 items is a perfectly valid case for an collection of items.
However - if you disagree and still want a way to convey a single element without IEnumerable semantics, you could overload Get with a method that takes a single object and returns a single IContract. This would take precedence over the params[] overload, since object would be a better match for a single input than params[] object.
This would look like:
public interface IMapper
{
IContract Get(object input);
IEnumerable<IContract> Get(params object[] input);
}
Assuming a null value means not found, your calling code would become:
var escalationMapper = _factory.GetEscalationMapper();
//we only get one object with a list of triggers but the interface returns a list. Change the interface?
var escalation = escalationMapper.Get(trackingGroupCode);
_factory.Release(escalationMapper);
response = Request.CreateResponse(contract == null ? HttpStatusCode.NotFound : HttpStatusCode.OK, contract);
I have to caution that it feels odd suggesting this, and I think it introduces dishonesty into the interface. I also think there is great potential to break any existing code that also calls the interface with a single input.
As for replacing object, you could always add some marker interface like IContractInput and pass that into Get instead of object:
public interface IContractInput { /* Intentionally empty */ }
And then, mark any input class with IContractInput:
public class SomeInput : IContractInput { /* implementation.. */ }
That way the methods could be strongly typed to take IContractInput instead of a generic object type.
It's a tradeoff. The goal is to fit the type expected by the client. The tradeoff is between 1) having an additional class and 2) forcing an existing type to change.
The pro of 1) is that an existing type remains intact (assuming it does presently make the most sense as the type it is, returning a single IContract); the con of 1) is that it requires more code and more dependencies.
The pro of 2) is that code size and number of dependencies remain lower; the con of 2) is that you subvert the project's types design by changing a type to return a list that will always contain a single element, purely for the sake of the client's expectations.
In strongly typed languages, the types system is intended to be there as an aid to the programmer. The greater verbosity buys the benefits of the type system, and subverting that system doesn't help very much with reducing the verbosity, yet loses the benefits of that type system. As such, I would resolve this in strongly-typed languages with an adapter, not by changing the interface.
In other words, resolve the situation with the principle of least surprise ( https://en.wikipedia.org/wiki/Principle_of_least_astonishment ). If another programmer on the project (or you, yourself, in some months' time) would ordinarily expect an instance of EscalationMapper to return a sole IContract, and so would be surprised to see it return an IEnumerable, then use an adapter ( https://en.wikipedia.org/wiki/Adapter_pattern ). If, conversely, they'd be surprised to see it return a single item, then change the interface.

Safe convert function

Can someone explain me this code, especially I'm not sure how generic function as parameter works:
result.Notes= orderInfo.Notes.SafeConvert(x => (Communication.OrderNotes)x);
public static TOut[] SafeConvert<TIn, TOut>(
this TIn[] input,
Func<TIn, TOut> converter)
{
if (input == null)
{
return null;
}
return input
.Where(i => i != null)
.Select(converter)
.ToArray();
}
SafeConvert is a generic extension method. The first parameter (an array of the generic type TIn) is implicitly added when the method is invoked on an array of some type (in this case maybe a note?). The method also requires an function as a parameter. This function must take an instance of the type TIn and return a TOut instance. So, you'd invoke this method on an array of some type, supply a lambda expression or a delegate function, and it will return an array of whatever type your supplied function returns. It does this by using Linq to filter out nulls, run each item in the array through the method, then return the enumeration of those items as an array.
In the implementation you've given, it takes the "Notes" of "orderInfo" and explicitly casts them to "CommunicationOrderNotes."
Here's another way you could invoke the method.
var decimals = new [] {5, 3, 2, 1}.SafeConvert(someInt => (decimal) someInt);
This is what's known as an extension method. It's a static function that allows you to "add" methods to types without modifying the original code. It's somewhat analogous to the Decorator Pattern but there's controversy about whether it's actually an implementation of that particular pattern.
"Under the hood," at least, extension methods are just "syntactic sugar" for calling a static method, but you can call them as if they were an instance method of the extended object (in this case, arrays).
The <TIn, TOut> part means that TIn and TOut are some type you haven't specified yet (but that you intend to specify what they actually are when you go to use the class). To understand the purpose of this, think of a Linked List - really, the implementation of a Linked List of integers isn't any different than the code for a Linked List of strings, so you'd like it to be the case that you can create a single class and specify later that you want a list of integers or a list of strings or whatever. You definitely would not want to have to create an implementation for every single possible type of object - that would require a massive amount of redundant code.
Now, for the LINQ query:
return input
.Where(i => i != null)
.Select(converter)
.ToArray();
LINQ (Language Integrated Query) is a mechanism for querying different types of collections using a single syntax. You can use it to query .NET collections (like they're doing here), XML documents, or databases, for example.
LINQ Queries take an anonymous function of some kind and apply the operator to the collection in some way (see below).
Going through this query;
.Where(i => i != null)
As the name suggests, Where applies a filter. When applied to a collection, it returns a second collection with all of the elements of the first collection that match the filter condition. The
i => i != null
bit is the anonymous function that acts as a filter. Basically, what this is saying is "give me a collection with all of the members of the array that aren't null."
The Select method applies a transform to every element of the collection and returns the result as a second collection. In this case, you apply whatever transformation you passed in as an argument to the method.
It might sound slightly odd to think of code as data, but this is actually very routine in some other languages like F#, Lisp, and Scala. ("Under the hood", C# is implementing this behavior in an object-oriented way, but the effect is the same).
The basic idea of this function, then, is that it converts an array of one type to an array of a second type, filtering out all of the null references.

Is there a benefit to using the c# out/ref keyword to "return" > 1 item in a method, instead of an object

Returning multiple things from a method, involves either:
returning an object with properties OR
using the out keyword to simply modify incoming parameters
Is there a benefit to using one system or the other? I have been using objects, but just discovered the out keyword, so wondering if I should bother refactoring.
You shouldn't bother refactoring just to utilize out parameters. Returning a class or struct would be preferred as long as structure is reusable.
A common use for out parameters which I would suggest using is to return a status for a call with that is possible to fail. An example being int.TryParse.
It has the possibility of failing, so returning a bool makes it easy to determing whether or not you should use the out parameter.
Another possible solution to returning multiple values from a method would be to use a Tuple. They can return n number of results. E.g.
public Tuple<bool, bool, string> MyMethod()
{
return new Tuple<bool, bool, string>(false, true, "yep");
}
In general, if the object that you are returning is not used anywhere else outside of the return value of your method or a group of similar methods, it is a good indication that you should refactor. When you need to create a special class simply to be used as a return value of a method, it means that you are working around C#'s inability to return multiple values from a method, so the out keyword may be a very good option for you.
On the other hand, if you use the multi-part return value in other places, such as storing them in collections or passing as arguments to other methods, there's probably no need to refactor, because the return object is meaningful.
Compare these two methods:
interface DictionaryReturn<T> {
T Value {get;}
bool Success {get;}
}
...
class Dictionary<K,V> {
...
public DictionaryReturn<V> TryGetValue(K key) {
...
}
}
or
class Dictionary<K,V> {
...
public bool TryGetValue(K key, out V res) {
...
}
}
The first case introduces a special DictionaryReturn<T> class that provides the value and an indicator that the value was found in the dictionary. There is rarely, if ever, a reason to store or use DictionaryReturn<T> objects outside the call to TryGetValue, so the second option is better. Not surprisingly, it is the second option that the designers of the .NET collections library have implemented.
I prefer to use Object with properties. If you use out keyword, you need to define it in other line. It is not as clear as return Object;
The reason to use out keyword is to ensure that code inside the method always sets a value to the out parameter. It's a compile time check that what you intended to do in the function, you did do.

Generic method to cast one arbitrary type to another in c#

I want to do something like this:
public static TResult MyCast<TSource, TResult>(TSource item)
{
return (TResult)item;
}
Without restrictions on TSource or TResult and avoiding unnecessary boxing if possible.
Edit: I want to stress out, that I want a simple casting of types, not elaborate type conversion here. It would be perfectly ok to fail at casting, say string to int.
Is there any sane way to do this using CLR 2.0?
Edit: this is a simplified version, so it's pretty useless, yes.
But consider casting generic collections, such as this:
public static Dictionary<string, TResult> CastValues<TSource, TResult>(this Dictionary<string, TSource> dictionary)
After some discussions with my co-workers, it seems like there's no simple way to implement such a feature (if at all possible), so I'm stuck with code bloat of several very simple methods for different situations (i.e. up- and downcast of reference types and casting of some value types) :(
Too bad I can't use .NET 4.0 with all it's dynamic et al goodness.
How would
x = MyCast<SourceType, ResultType>(y)
be any more useful than
x = (ResultType)y ?
This is straightforward when TSource and TResult are both reference types.
If one or the other are value types, how do you want it to work? Value types can't inherit from each other, so it's not a matter of doing an up- or down-cast. You might expect numeric conversions between, say, int and double, but you'd have to code these yourself: .NET doesn't treat them as typecasts. And conversion between, say, DateTime and string involves more intelligence (what format? which culture? etc.).
If you're just handling reference types then this method can be a one-liner. If you want to handle value types as well then you'll need to write special case code for the various combinations.
Edit: Convert.ChangeType does a reasonable job at encapsulating the various conversions between value types. However you mentioned you're keen not to introduce boxing: Convert.ChangeType isn't generic and it takes an object.
I think that the problem you are trying to solve is the same as the problem that you cannot cast a collection of one type to a collection of another type.
eg
class Obj1
{}
class Obj2:Obj1
{}
List<Obj2> srcList = GetList();
List<Obj1> castedList=(List<Obj2>) srcList;//this line wont compile
I have not done much at actually looking at the CLR code
However on the asuumption that it is like C++ what you would have here is actually different values stored in the collection. In other words srcList would contain a list of pointers to object 2's interface in castedList you would have a pointer to the the interface of the object 1's within object 2.
In order to resolve this you would need to have your casting function iterate through each of the items within the collection. However in order to be able to iterate through the items the list would have to implement some sort of enumeration interface. So the enumeration interface would need to be a constraint on the casting function.
So the answer would therefore be no.
However if you were prepared to implement this with restrictions on the in types you could have:
static class ListCast<TSource,TResult,TItemType>
where TSource:IEnumerable<TItemType>
where TResult:IList<TItemType>,new()
{
static TResult Cast(TSource list)
{
TResult castedList=newTResult();
foreach(TtemType item in list)
{
castedList.Add(TItemType)item);
}
return castedList;
}
}
you can just do this:
public static TResult MyCast<TSource, TResult>(TSource item)
{
return (TResult)((object)item);
}
Would love to hear how this could be bad.

Categories