Is it possible to use List<T>.Contains(...)? - c#

I am trying to to create a generic cache class that will hold a list of objects, and will expose a method that enables to check if an instance of an object is already cached based on Id property:
public class CacheService<T> where T : BaseModel
{
private List<T> _data = new List<T>();
public void Check(T obj)
{
if (_data.Contains(r => r.Id.Equals(obj.Id))
{
//Do something
}
}
}
public class BaseModel
{
public int Id { get; set; }
}
I am getting a compiler error on the Contains() command, saying:
Cannot convert lambda expression to type 'T' because it is not a delegate type
How can I achieve my goal?

You can use Linq:
bool contains = _data.Any(r => r.Id.Equals(obj.Id));
or List.Exists:
bool contains = _data.Exists(r => r.Id.Equals(obj.Id));

Use the LINQ function Any instead of Contains. For List<T>, the Contains method is defined to take a T.

Related

Casting List of objects to a IList with the interface of the object

I'm having a bit of a problem implementing an interface from a nuget package.
There is a property in the interface that looks like this: IList<IInterfaceInstance> Implements {get;}
My problem is casting from List<InterfaceInstance> to IList<IInterfaceInstance>.
This is what I'm trying to do and it gives me the following exception:
Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var ins1 = new InterfaceInstance() {Id = "1"};
var ins2 = new InterfaceInstance() {Id = "2"};
List<InterfaceInstance> imps = new List<InterfaceInstance>() {ins1, ins2};
IList<IInterfaceInstance> implements = imps as IList<IInterfaceInstance>;
foreach( var imp in implements) {
Console.WriteLine(imp.Id);
}
}
private class InterfaceInstance : IInterfaceInstance
{
public string Id { get; set; }
public string Name { get; set; }
}
public interface IInterfaceInstance
{
public string Id { get; set; }
public string Name { get; set; }
}
}
As per the documentation:
The as operator explicitly converts the result of an expression to a
given reference or nullable value type. If the conversion is not
possible, the as operator returns null.
In general, generic types don't allow variance of its arguments, meaning you cannot cast to a different type. This is why implements is null and it fails when trying to perform the foreach.
To achieve your intention, you'll have to cast each independent item to IInterfaceInstance, not the whole list.
You could use linq to select a new ienumerable, passing a lambda to cast each InterfaceInstance as IInterfaceInstance:
IList<IInterfaceInstance> implements = imps.Select(interfaceInstance => (IInterfaceInstance)interfaceInstance).ToList();
IList is not covariant, so you can't cast List<class> to IList<interface>, and your as operator returns null. use IEnumerable<IInterfaceInstance> instead if all you want to do is iterate over the items.
You cannot cast directly to IList like that because it is not co-variant. Otherwise you would be able to add something that implements IInterfaceInstance but isn't InterfaceInstance into a list that should only have InterfaceInstance. Instead you'd have to cast each item like this.
IList<IInterfaceInstance> implements = imps
.Cast<IInterfaceInstance>()
.ToList() as IList<IInterfaceInstance>;
Alternatively you can cast to IEnumerable<IInterfaceInstance> because it is co-variant because it only allows you to pull items out.
IEnumerable<IInterfaceInstance> implements = imps as IEnumerable<IInterfaceInstance>;

How to cast a 'list of classes' to a 'list of its interface'?

I need to cast a class list to its own interface list.
So I have interface Demo_Interface and two classes based on Demo_Interface ,
Now I create list of classes like List<Test_Class1>
And I have a function with List<Demo_Interface> parameter.
Here's interface :
interface Demo_Interface
{
int test_int { get; set; }
}
Here's Entire Code :
using System;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
///// Main Interface
interface Demo_Interface
{
int test_int { get; set; }
}
//// Class 1 Based On Demo_Interface
class Test_Class1 : Demo_Interface
{
public int test_int { get; set; }
public string test_string { get; set; }
}
///// Class 2 Based On Demo_Interface
class Test_Class2 : Demo_Interface
{
public int test_int { get; set; }
public string test_string { get; set; }
}
//// And Main Class
class Main_Class
{
public List<Test_Class1> class_list_1 { get; set; }
public List<Test_Class2> class_list_2 { get; set; }
public Main_Class()
{
class_list_1 = new List<Test_Class1>() { };
class_list_2 = new List<Test_Class2>() { };
}
}
//// Console Main
static void Main(string[] args)
{
var new_main_class = new Main_Class();
Output_Class(new_main_class.class_list_1); ///// ==> ERROR
Console.ReadKey();
}
//// Simple Function for do something with interface
static void Output_Class(List<Demo_Interface> inter_input)
{
for (int i = 0; i < inter_input.Count; i++)
{
Console.WriteLine("{0} - {1}",i, inter_input[i].test_int);
}
}
}
}
How Can I cast List<Test_Class1> to List<Demo_Interface> , When Test_Class1 uses Demo_Interface?
You can try
List<Test_Class1> testDemo = new List<Test_Class1>(); //list of Test_Class1 instances
List<Demo_Interface> result = testDemo.ToList<Demo_Interface>();
This is safe because we are not directly casting testDemo to its interface. We are keeping testDemo as it is and we are creating result which is list of Demo_Interface
You cannot cast a List<ClassThatImplementsInterface> as a List<IInterfaceItImplements>.
If you could, and you did this:
var classList = new List<ClassThatImplementsInterface>();
var interfaceList = (List<IInterfaceItImplements>)classList;
... then you would be able to do this:
interfaceList.Add(new SomeOtherClassThatImplementsTheInterface);
But casting the list doesn't create a new list. In the above example there aren't two lists. There are two variables with references to the same list. If you could cast as seen above, you would be able to define a list of one type and add a completely different type to it. The compiler prevents that.
You could
create a new List<IDemoInterface> and add the items to it. (Or an array, IEnumerable, etc.)
Leave the list as-is, and just cast individual items when/if you need to. In most cases we wouldn't need to cast something as an interface it implements.
If we need to cast a whole collection as a different type, it's likely because we're passing it as an argument.
That's actually a good reason not to define a method argument as a collection type like a List<T> which can be modified unless it's our intent to modify the collection.
That's one reason why we pass less-specific collection types, like IEnumerable<T>.
Suppose the method argument looks like this:
void MethodINeedToPassTheArgumentTo(IEnumerable<IDemoInterface> items)
Now we can take our List<TestClass> and do this:
MethodINeedToPassTheArgumentTo(testClassList.Cast<IDemoInterface>);
We're not creating a new collection. We're passing a reference that allows the other method to view the items in the list, each individually cast as IDemoInterface. For practical purposes it looks to the other method like a collection of IDemoInterface, and that's okay because the other item can't modify the collection. It can't attempt to add other types into the List<TestClass>.
If you need only to enumerate through the List<Demo_Interface> like shown in example, you don't have to do any kind of explicit casting. List<T> implements IEnumerable<T> which is covariant generic type.
Covariance for collections enables implicit conversion of a collection of a more derived type to a collection of a less derived type
In your case, List<Test_Class1> implements IEnumerable<Test_Class1>, but since Test_Class1 implements Demo_Interface, you can take advantage of generics variance and write, for example, something like this:
IEnumerable<Test_Class1> col = new List<Test_Class1>();
IEnumerable<Demo_Interface> colImplicit = col;
That basically means that your Output_Class method can take IEnumerable<Demo_Interface> argument and you'll be able to pass both lists without casting them explicitly using Cast<T> or creating a new collection using ToList<T>.
private void Output_Class(IEnumerable<Demo_Interface> inter_input)
{
// do your thing
}
// Method invocation
Output_Class(new_main_class.class_list_1);

Trying to Utilise a generic <T> collection

I am using C# and I thought I finally had the chance to understand a Generic type. I have several strongly typed objects that need the same static method. Rather than create one static method for each type I thought I could make it generic. Something I have never done and really wanted too.
Here is where I invoke it.
bool isDuplicate = Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
Here is my static method which resides in a static class called Utilities.
public static bool GetDuplicates<T>(List<T> pBookings)
{
foreach (var item in pBookings)
{
var myVal = item.bookingId
}
return true;
}
So I want to get at the values within var item inside the foreach loop so I can do comparisons. It's definately passed pBookings because I can hover and they have a .Count() with a collection of my strongly typed object. I am missing something here, possibly a casting process. I was wondering if anyone could advise me where I am coming up short.
var myVal = item.bookingId - I cannot get the bookingID from item because I am lacking in some basic understanding here. bookingId doesn't exist, I just get access to extension methods such as .toString and .equals
ANSWER OF SORTS What I did based on all of your really helpful assistance. I utilised Anderson Pimentel. I'm probably still off the mark but wanted to garner anyones thoughts here.
So basically I have several booking models, all need checking for duplicates. I really wanted to understand Generics in this way. So what I did is. Created a base class.
public class BookingBaseModel
{
public int BookingID { get; set; }
public DateTime BookingStartDateTime { get; set; }
public DateTime BookingEndDateTime { get; set; }
}
Then had my booking classes all inherit whats common to all. Like this...
public class RoomBookingModel : BookingBaseModel
{
public string RoomName{ get; set; }
}
public class vehicleBookingModel : BookingBaseModel
{
public string vehicleName{ get; set; }
}
Then in my utilities static helper I did this..
public static void GetDuplicates<T>(List<T> items) where T : BookingBaseModel
{
foreach (var item in items)
{
int myId = item.ID;
DateTime startDateTime = item.BookingStartDateTime;
DateTime endDateTime = item.BookingEndDateTime;
//Do you logic here
}
}
Then finally did something like this in corresponding controller action.
RoomController...
Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
VehicleController....
Utilities.GetDuplicates<VehicleBookingModel>(vehicleBookings);
Is this basically how we go about using generics in this way?
The compiler has no hint of what type is T. If you have a base class (or an Interface) which has the bookingId attribute, like BaseModel, you can constrain the generic type like the following:
public class BaseModel
{
public int Id { get; set; }
}
public static bool GetDuplicates<T>(List<T> items) where T : BaseModel
{
foreach (var item in items)
{
var myId = item.Id;
//Do you logic here
}
return true;
}
Once you're inside your GetDuplicates method, you have lost all knowledge of the RoomBookingModel type. That's the point of generic methods - they should be able to act on whatever type has been passed in to them, e.g. the logic within them should be generic across any type.
So your foreach loop is fine - you know you've been given a list of something, and you know lists can be iterated. But inside that foreach, item is just a T. You don't know what actual type it is because any type could have been passed in. So it doesn't make sense to access a specific property or method off of item - for example, what if I called GetDuplicates passing in a List<int>? It wouldn't have a bookingId property.
As written by others, you don't know anything of T. A classical solution, used by LINQ (see for example GroupBy) is to have your method receive a delegate that does the key-extraction, like:
public static bool GetDuplicates<T, TKey>(List<T> pBookings, Func<T, TKey> selector)
{
foreach (var item in pBookings)
{
TKey key = selector(item);
}
return true;
}
You then use it like:
GetDuplicates(pBookings, p => p.bookingId);
If you like to use a generic method, you have to provide also a generic method, which is able to generate a key out of the specified type T. Luckily we have LINQ which already provides the needed parts to build your generic method:
internal class Extensions
{
public static IEnumerable<T> GetDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return source.GroupBy(keySelector)
.Where(group => group.Skip(1).Any())
.SelectMany(group => group);
}
public static bool ContainsDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return GetDuplicates(source, keySelector).Any();
}
}
By having this (and type inference) you can use these methods e.g. by calling:
var hasDuplicates = roomBookings.ContainsDuplicates(item => item.bookingId);
if(hasDuplicates)
{
Console.WriteLine("Duplicates found:");
foreach (var duplicate in roomBookings.GetDuplicates(item => item.bookingId))
{
Console.WriteLine(duplicate);
}
}
I wonder if generics is really the tool for the job here. Your needs would be better served if each of your strongly typed objects shared a common interface.
"I have several strongly typed objects that need the same static method."
In this situation, all of the classes must share a common feature, such as, for instance, a property BookingId.
So, you'd need to formalize this by extracting this common interface:
public interface IBooking
{
int BookingId{ get; }
}
Make sure that every one of your strongly typed items implements the interface:
public class RoomBooking : IBooking
{
//etc...
}
And now make your static method accept IBooking instances:
public static bool GetDuplicates(IEnumerable<IBooking> pBookings)
{
//does pBookings contain items with duplicate BookingId values?
return pBookings.GroupBy(b => b.BookingId).Any(g => g.Count() > 1);
}
An easy read that isn't obfuscated by the unnecessary use of generics.
Since there are no constraints or hints about what T is, the compiler does not have enough information. Consider
bool isDuplicate = Utilities.GetDuplicates<int>(roomBookings);
Clearly an int does not have a bookingId member.
Every possible specific type for T would have to have a common base class or interface that has a bookingId, and even then you would have to add a generic constraint to your method signature to access that.
Perhaps you are looking for something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Duplicates
{
public static class EnumerableExtensions
{
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter, IEqualityComparer<I> comparer )
{
var hashSet = new HashSet<I>(comparer);
foreach (var item in enumerable)
{
var identity = identityGetter(item);
if (hashSet.Contains(identity)) return true;
hashSet.Add(identity);
}
return false;
}
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter)
{
return enumerable.HasDuplicates(identityGetter, EqualityComparer<I>.Default);
}
}
public class Booking
{
public int BookingId { get; set; }
public string BookingName { get; set; }
}
public class Customer
{
public string CustomerId { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var bookings = new List<Booking>()
{
new Booking { BookingId = 1, BookingName = "Booking 1" },
new Booking { BookingId = 1, BookingName = "Booking 1" }
};
Console.WriteLine("Q: There are duplicate bookings?. A: {0}", bookings.HasDuplicates(x => x.BookingId));
var customers = new List<Customer>()
{
new Customer { CustomerId = "ALFKI", Name = "Alfred Kiss" },
new Customer { CustomerId = "ANATR", Name = "Ana Trorroja" }
};
Console.WriteLine("Q: There are duplicate customers?. A: {0} ", customers.HasDuplicates(x => x.CustomerId));
}
}
}

Cast array of unknowClass to array of otherClass in c#

How Can I dynamically cast at runtime.That is I am passing a child class object in the parent class object.
public abstract class tObject
{
public tObject[] someMthode(){;}
}
public class myClass : tObject
{
public string Oth0 { get; set; }
public string Oth1 { get; set; }
public string Oth2 { get; set; }
}
I want
myClass mc=new myClass();
tObject to=mc;
myClass[] mcArray=(myClass[])mc.someMthode();//System.InvalidCastException
//Unable to cast object of type 'tObject[]' to type 'myClass[]'
but when check any element of mcArray is correct
if (mcArray[0] is myClass)
{
//return true and run this ;
}
In fact I want cast when a method return array of tObject according to the base class :
subClass[] mcArray=(subClass[])instanceOfsubClass.someMthode()
subClass or myClass and ... are unknown class , and i don't know theirs name.
Solution
public T[] Cast<T>(tObject[] mcArray ) where T : tObject
{
if (mcArray != null)
{
int cnt = mcArray.GetLength(0);
T[] t = new T[cnt];
for (int i = 0; i < cnt; i++)
{
t[i] = (T)mcArray[i];
}
return t;
}
return null;
}
Thanks all for replies.
C# does not support that kind of array conversion. C# does -- unfortunately! -- support dangerous array covariance. That is, if you had an array myClass[] then you could implicitly convert it to an array tObject[]. This means that you can do this:
Tiger[] tigers = new Tiger[10];
Animal[] animals = tigers;
animals[0] = new Turtle();
and now we have a turtle inside an array of tigers. This crashes at runtime.
That's bad enough, but you want it to go the other way -- I have an array of animals and I'd like it to be treated as an array of tigers. That does not work in C#.
As other answers have noted, you'll need to make a second array and copy the contents of the first to the second. There are a number of helper methods to do so.
Maybe?
myClass mc = new myClass();
tObject to = mc;
//myClass[] mcArray = (myClass[])mc.someMthode();//System.InvalidCastException
//Unable to cast object of type 'tObject[]' to type 'myClass[]'
var mcArray = Array.ConvertAll(mc.someMthode(), item => (myClass) item);
Well, you can call IEnumerable.Cast for that:
var myArr = mc.someMethod().Cast<MyClass>().ToArray();
As MyClass[] implements IEnumerable<MyClass>.
EDIT: What you want is quite dangerous. Look the following code:
subClass[] mcArray=(subClass[]) new BaseClass[] {...};
If this conversion would work we could now simply make the following also:
mcArray[0] = new AnotherClass();
Now you have an array of subClasses containin one item of AnotherClass also.
If you do not know the type at compile-time you cannot expect the compiler to provide any compile-time-logic for a type it doesn´t know. Thus casting to an unknown type and calling members on isn´t supported. However you may achieve this using reflection:
var runtimeType = myArr[0].GetType();
var mi = runtimeType.GetMethod("SomeMethod");
var value = mi.Invoke(myArr[0]);
This is similar to the call
var value = ((subClass)myArr[0]).SomeMethod();
Why not solve it one step up the chain and make someMethod (spelling corrected) generic:
public abstract class tObject<T> where T:tObject
{
public T[] someMethod(){;}
}
public class myClass : tObject<myClass>
{
public string Oth0 { get; set; }
public string Oth1 { get; set; }
public string Oth2 { get; set; }
}
now myClass.someMethod returns a myclass[] and that problem is solved. However, since I'm assuming that tObject does other things that just create an array of tObjects, it may cause other problems that aren't inferrable from the code you provided.
Plus it's not 100% foolproof. There's nothing stopping you (or someone else) from defining:
public class myWeirdClass : tObject<myClass>
{
}
now myWeirdClass.someMethod also returns a myClass[], and the pattern is broken. Unfortunately there's no generic constraint that requires that the generic parameter be the defining class itself, so there's no way to prevent this flaw at compile-time.
Another option may be to move the array creation outside of the class itself, since it is a code smell in itself:
public class ObjectFactory<T> where T:tObject
{
public T[] SomeMethod()
{
... create an array of Ts
}
}

C#: Declaring and using a list of generic classes with different types, how?

Having the following generic class that would contain either string, int, float, long as the type:
public class MyData<T>
{
private T _data;
public MyData (T value)
{
_data = value;
}
public T Data { get { return _data; } }
}
I am trying to get a list of MyData<T> where each item would be of different T.
I want to be able to access an item from the list and get its value as in the following code:
MyData<> myData = _myList[0]; // Could be <string>, <int>, ...
SomeMethod (myData.Data);
where SomeMethod() is declared as follows:
public void SomeMethod (string value);
public void SomeMethod (int value);
public void SomeMethod (float value);
UPDATE:
SomeMethod() is from another tier class I do not have control of and SomeMethod(object) does not exist.
However, I can't seem to find a way to make the compiler happy.
Any suggestions?
Thank you.
I think the issue that you're having is because you're trying to create a generic type, and then create a list of that generic type. You could accomplish what you're trying to do by contracting out the data types you're trying to support, say as an IData element, and then create your MyData generic with a constraint of IData. The downside to this would be that you would have to create your own data types to represent all the primitive data types you're using (string, int, float, long). It might look something like this:
public class MyData<T, C>
where T : IData<C>
{
public T Data { get; private set; }
public MyData (T value)
{
Data = value;
}
}
public interface IData<T>
{
T Data { get; set; }
void SomeMethod();
}
//you'll need one of these for each data type you wish to support
public class MyString: IData<string>
{
public MyString(String value)
{
Data = value;
}
public void SomeMethod()
{
//code here that uses _data...
Console.WriteLine(Data);
}
public string Data { get; set; }
}
and then you're implementation would be something like:
var myData = new MyData<MyString, string>(new MyString("new string"));
// Could be MyString, MyInt, ...
myData.Data.SomeMethod();
it's a little more work but you get the functionality you were going for.
UPDATE:
remove SomeMethod from your interface and just do this
SomeMethod(myData.Data.Data);
Delegates can really help simplify this, and still keep things type-safe:
public void TestMethod1()
{
Action<SomeClass, int> intInvoke = (o, data) => o.SomeMethod(data);
Action<SomeClass, string> stringInvoke = (o, data) => o.SomeMethod(data);
var list = new List<MyData>
{
new MyData<int> { Data = 10, OnTypedInvoke = intInvoke },
new MyData<string> { Data = "abc", OnTypedInvoke = stringInvoke }
};
var someClass = new SomeClass();
foreach (var item in list)
{
item.OnInvoke(someClass);
}
}
public abstract class MyData
{
public Action<SomeClass> OnInvoke;
}
public class MyData<T> : MyData
{
public T Data { get; set; }
public Action<SomeClass, T> OnTypedInvoke
{ set { OnInvoke = (o) => { value(o, Data); }; } }
}
public class SomeClass
{
public void SomeMethod(string data)
{
Console.WriteLine("string: {0}", data);
}
public void SomeMethod(int data)
{
Console.WriteLine("int: {0}", data);
}
}
Just use an ArrayList and forget the MyData<T> type.
ArrayList myStuff = getStuff();
float x = myStuff.OfType<float>().First();
SomeMethod(x);
string s = myStuff.OfType<string>().First();
SomeMethod(s);
The problem with MyData<T> is that you're expecting the compiler to check a type that is only known at runtime. Compilers check types that are known at compile time.
You can't do it the way you want.
When an instance of a generic class is initialized, it is bound to particular type. Since you want to hold objects of different types in your list, you have to create an instance bound to the least common denominator — in your case it's Object.
However, that means that Data property now will return an object of type Object. The compiler cannot infer the actual data type at compile time, so it can choose the appropriate SomeMethod overload.
You have to either provide an overload of SomeMethod that takes Object as a parameter, or remove the requirement to hold different such different types in your collection.
Or you can go with a standard IEnumerable collection (like Array) and use the OfType<> extension method to get the subset of the collection of particular type.
In that case you need MyData<object> since that is the only thing those types have in common.
You can create a generic wrapper for SomeMethod and check for the type of the generic argument, then delegate to the appropriate method.
public void SomeMethod<T>(T value)
{
Type type = typeof(T);
if (type == typeof(int))
{
SomeMethod((int) (object) value); // sadly we must box it...
}
else if (type == typeof(float))
{
SomeMethod((float) (object) value);
}
else if (type == typeof(string))
{
SomeMethod((string) (object) value);
}
else
{
throw new NotSupportedException(
"SomeMethod is not supported for objects of type " + type);
}
}
Suggested wildcards a while back here. Closed as "won't fix" :(
Generics allow you to specify one type for the whole list when you create the list, for example a list for storing int would be created like this
var myData = new MyData<int>();
If you want to store multiple types in the same generic list you can specify a common base type or interface for those types. Unfortunately in your case the only common base type for the types you want to store would be object.
var myData = new MyData<object>();
But you can just use the non-generic list for storing objects.
Inherit MyData<T> from a non-generic MyData class and make a list of that.
This way, you can't automatically resolve the overload. You have to do it manually.
abstract class MyData {
protected abstract object GetData();
protected abstract Type GetDataType();
public object Data {
get { return GetData(); }
}
public Type DataType {
get { return GetDataType(); }
}
}
class MyData<T> : MyData {
protected override object GetData() { return Data; }
protected override Type GetDataType() { return typeof(T); }
public new T Data {
get { ... }
}
}

Categories

Resources