My question is somewhat similar to
Generic List of Generic Interfaces not allowed, any alternative approaches?
If I have an interface such as
public interface IPrimitive
{
}
public interface IPrimitive<T> : IPrimitive
{
T Value { get; }
}
public class Star : IPrimitive<string> //must declare T here
{
public string Value { get { return "foobar"; } }
}
public class Sun : IPrimitive<int>
{
public int Value { get { return 0; } }
}
Then I have a list
var myList = new List<IPrimitive>();
myList.Add(new Star());
myList.Add(new Sun());
When looping through this list, how do I get the Value property?
foreach (var item in myList)
{
var value = item.Value; // Value is not defined in IPrimitive so it doesn't know what it is
}
I'm not sure how this is possible.
Thanks,
Rob
You can take advantage of dynamic:
foreach (dynamic item in myList)
{
var value = item.Value;
}
The dynamic type enables the operations in which it occurs to bypass compile-time type checking. Instead, these operations are resolved at run time
You could do something like this:
public interface IPrimitive
{
object Value { get; }
}
public interface IPrimitive<T> : IPrimitive
{
new T Value { get; }
}
public class Star : IPrimitive<string> //must declare T here
{
public string Value { get { return "foobar"; } }
object IPrimitive.Value { get { return this.Value; } }
}
public class Sun : IPrimitive<int>
{
public int Value { get { return 0; } }
object IPrimitive.Value { get { return this.Value; } }
}
You're then able to get the value out as an object when you only have IPrimitive.
of course not, your value is going to be of different types..... so you will have to downcast to the real type to get at the different values.
Basically your interface is failing. Its not "A common interface" It's more a "similar interface"
If you don't want to do casting, then you will have to find an interface which is common to both of them.
You can move you Value property to base interface.
public interface IPrimitive
{
object Value { get; }
}
How do you want to procced value in the loop it has different type?
Related
I run into a compiler error that I am not sure how to resolve it.
Basically, I have a few enum classes described below.
I created abstract classes myTool and myTools deriving from myTool.
The compiler for some reason does not like the way I structured the constructor for MyTools and threw error
CS0030: Can not convert type int to type T.
Please advice me how to resolve this.
public enum TOOLS
{
HAMMER =1,
DRILL = 2,
SCREWDRIVER =3,
VACUUM=4
}
public enum EQUIPMENTS
{
MOWER=1,
TRIMMER=2,
SNOWBLOWER=3
}
public abstract class MyTool
{
protected T _myStuff
int quantity
double price
public MyTool(T t)
{
_myStuff =t;
}
... properties...
}
public abstract class MyTools<T>:myTool<T>
where T:System.Enum
{
protected MyTool<T>[] _myTools;
public MyTool<T> this[int i]=> this._myTools[i];
public MyTools(int count, T t):base(t)
{
_myTools = new MyTools<T>[count];
for (int i=0; i<count;i++)
{
_myTools[i]=(T)(i+1);
}
}
}
You can convert an int into a generic type constrained as System.Enum like this:
T enumValue = (T)Enum.ToObject(typeof(T), intValue);
or simply
T enumValue = (T)(object)intValue;
You can use generic type converter
public static class TConverter
{
public static T ChangeType<T>(object value)
{
return (T)ChangeType(typeof(T), value);
}
public static object ChangeType(Type t, object value)
{
TypeConverter tc = TypeDescriptor.GetConverter(t);
return tc.ConvertFrom(value);
}
public static void RegisterTypeConverter<T, TC>() where TC : TypeConverter
{
TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC)));
}
}
and usage:
TConverter.ChangeType<T>(intValue);
it is from here: https://stackoverflow.com/a/1833128/2286743
I had an idea about which I couldn't find any direct syntax. I was wondering if it was possible to overload a reference type so that when it is referenced in a certain way it redirects its reference type into a new one.
I'd like to show an example about this:
public class MyClass
{
public ICollection<int> CollectionProperty { get; private set; }
public MyClass()
{
this.CollectionProperty = new List<int>();
}
}
This is just a simple class, but when MyClass is referenced, for example in a foreach, I'd like it to reference its inner collection like this:
MyClass instance = new MyClass();
foreach(int item in instance)
{
// do stuff
}
So here an item would be an int value of the class's collection's.
It was just something I was curious about, I don't know if it's even possible, maybe with some kind of reference overloading, or I don't know.
Thank you for your answers!
You could implement IEnumerable in order to enable foreach functionality.
public class MyClass<T> : IEnumerable<T>
{
public List<T> Collection { get; set;}
public T this[int index]
{
get { return Collection[index]; }
set { Collection.Insert(index, value); }
}
public IEnumerator<T> GetEnumerator()
{
return Collection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public MyClass()
{
Collection = new List<T>();
}
}
public class Program
{
public static void Main()
{
var instance = new MyClass<int>();
instance.Collection.Add(1);
instance.Collection.Add(2);
instance.Collection.Add(3);
foreach(int item in instance)
Console.WriteLine(item);
}
}
Output:
1 2 3
I have a following generic class:
public class SearchResult<T>
{
public int ResultCount { get; set; }
public IEnumerable<T> Result { get; set; }
}
I also have a Bird class, which implements IFlyble interface:
public class Bird : IFlyable
{
public void Fly() {}
}
public interface IFlyable
{
void Fly();
}
I also have a variable res of type object.
How do I check if res is a SearchResult<IFlyable> ?
I tryied this way:
if (res.GetType().IsAssignableFrom(typeof(SearchResult<IFlyable>)))
{
///
}
And this way:
if(res is SearchResult<IFlyable>)
{
///
}
But it does not seems to work.
The problem you are having is probably due to the fact that SearchResult<Bird> is not convertible to SearchResult<IFlyable> because SearchResult<T> is invariant in T.
C# only admitís generic type variance in interfaces and delegates. You need to define an ISearchResult<> interface that is covariant in its generic type.
In your case, if it’s accepatable that T Is only used as an output you could define such interface as follows:
public interface ISearchResult<out T>
{
int ResultCount { get; }
IEnumerable<T> Result { get; }
}
And now a ISearchResult<Bird> is a ISearchResult<IFlyable> because you’ve given the compiler enough information so that it can verify that the conversion is in fact safe
You can also try this using reflection, which also works and no need to create another interface.
static void Main()
{
var sr = new SearchResult<Bird>();
Console.WriteLine(IsSearchResultIFlyable(sr.GetType())
? "sr is SearchResult<IFlyable>"
: "sr is Not SearchResult<IFlyable>");
Console.ReadLine();
}
public static bool IsSearchResultIFlyable(Type t)
{
if (!t.IsGenericType) return false;
if (t.GetGenericTypeDefinition() != typeof(SearchResult<>)) return false;
var gr = t.GetGenericArguments();
return gr.Length == 1 && typeof(IFlyable).IsAssignableFrom(gr[0]);
}
I'm having some trouble creating my own List structure. I'm trying to create a List structure called SortedList. The objective is for it to Sort its items as soon as add a new item. This list will not get too big in the project I'm using it for (maybe 50-100 items at most). However, I was testing by adding a simple item of class Employee which has a Name property. And I want this SortedList to sort on employee's Name.
Here is my attempt.
The Employee class
public class Employee : IComparer<Employee>
{
public string Name { get; set; }
public Employee()
{
}
public int Compare(Employee x, Employee y)
{
return string.Compare(x.Name, y.Name,true);
}
}
Here is the SortedList class that I'm trying to create.
public class SortedList<T> : IEnumerable<T>
{
private List<T> _list;
public List<T> List
{
get { return _list; }
set { _list = value; }
}
private Employee EmployeeComparer = new Employee();
public SortedList()
{
_list = new List<T>();
}
public void Insert(T item)
{
if (!_list.Contains(item))
{
_list.Add(item);
Sort(_list);
}
}
private void Sort(List<T> list)
{
var type = typeof(T);
switch (type.Name)
{
case "Int32":
case "String":
list.Sort();
break;
case "Employee":
Employee EmployeeComparer = new Employee();
list.Sort(EmployeeComparer);
break;
}
}
public IEnumerator<T> GetEnumerator()
{
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
From program.cs I'm basically populating the SortedList with three instances of Employee objects and I expect it to Sort it by employee's Name property and in the out put I expect to see this.
Barry
Neil
Zach
class Program
{
static void Main(string[] args)
{
SortedList<Employee> list = new SortedList<Employee>();
list.Insert(new Employee() { Name="Zach"});
list.Insert(new Employee() { Name = "Neil" });
list.Insert(new Employee() { Name = "Barry" });
foreach (var item in list)
{
Console.WriteLine(item.Name);
}
}
}
But I get a compiler error. It says:
Severity Code Description Project File Line Suppression State
Error CS1503 Argument 1: cannot convert from 'ExtensingLists.Employee' to 'System.Collections.Generic.IComparer<T>' ExtensingLists C:\E Drive\VSProjects\C-Sharp Generics Course\ExtensingLists\ExtensingLists\SortedList.cs 57 Active
The error says line 57, which is this:
list.Sort(EmployeeComparer);
What am I doing wrong? Please advise. Thank you.
The concrete question you're asking about is like asking why
int f(object o) { return o is int ? o : 0; }
fails to compile. Even if you've checked that o has type int at run-time, at compile-time it still has type object, which means it can't be used as the return value. You'd need a cast to get that working:
int f(object o) { return o is int ? (int)o : 0; }
and the same applies to your code.
But there's something more fundamentally wrong. Your Employee shouldn't be implementing IComparer<Employee>. It should be implementing IComparable<Employee>, which specifies not that an Employee object knows how to compare two other Employee objects, but that it knows how to compare itself to another Employee object. And when you do that, you should be able to just call list.Sort(); without checking the type at all.
The List.Sort method can be made to work in multiple ways.
This method uses the default comparer Comparer.Default for type T to determine the order of list elements. The Comparer.Default property checks whether type T implements the IComparable generic interface and uses that implementation, if available. If not, Comparer.Default checks whether type T implements the IComparable interface. If type T does not implement either interface, Comparer.Default throws an InvalidOperationException.
So by making the below change, it will start working for you
public class Employee : IComparable<Employee> {
public string Name { get; set; }
public Employee() {
}
public int CompareTo(Employee other) {
return string.Compare(Name, other.Name, true);
}
}
and the Below change in public class SortedList<T> : IEnumerable<T> {
private static void Sort(List<T> list) {
var type = typeof(T);
list.Sort();
}
This is not the only way to do, but a preferable way to do when the Types are intrinsically Orderable. You can also use the IComparer<T> interface, but that is used when the Type needs to be sorted in a way that IComparable<T> does not or when the Type is not an IComparable<T>. I have listed all the code here together
class Program {
static void Main() {
SortedList<Employee> list = new SortedList<Employee>();
list.Insert(new Employee() { Name = "Zach" });
list.Insert(new Employee() { Name = "Neil" });
list.Insert(new Employee() { Name = "Barry" });
foreach (var item in list) {
Console.WriteLine(item.Name);
}
}
}
public class Employee : IComparable<Employee> {
public string Name { get; set; }
public int Age { get; set; }
public Employee() {
}
public int CompareTo(Employee other) {
return string.Compare(Name, other.Name, true);
}
}
public class EmployeeAgeComparer : IComparer<Employee> {
public int Compare(Employee x, Employee y) {
return x.Age - y.Age;
}
}
public class SortedList<T> : IEnumerable<T> {
private List<T> _list;
public List<T> List {
get { return _list; }
set { _list = value; }
}
private EmployeeAgeComparer EmployeeComparer = new EmployeeAgeComparer();
public SortedList() {
_list = new List<T>();
}
public void Insert(T item) {
if (!_list.Contains(item)) {
_list.Add(item);
Sort(_list);
}
}
private void Sort(List<T> list) {
if (typeof(T) == typeof(Employee))
list.Sort((IComparer<T>)EmployeeComparer);
else
list.Sort();
}
public IEnumerator<T> GetEnumerator() {
return _list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
I'm looking for a way to treat ALL .Net datatypes consistently so I can create the pattern below where any type implementing IGetValue<out T> will cast to IGetValue<object>. For some reason, if T is a struct, it doesn't work and I don't understand why. Is there a way I can implement the following pattern??
public interface IGetValue<out T>
{
T Value
{
get;
}
}
public class GetValue<T> : IGetValue<T>
{
public GetValue(T value)
{
_value = value;
}
private T _value;
public T Value
{
get { return _value; }
}
}
class Program
{
static void Main(string[] args)
{
IGetValue<string> GetString = new GetValue<string>("Hello");
IGetValue<int> GetInt = new GetValue<int>(21);
//This works!!!
if (GetString is IGetValue<object>)
{
Console.WriteLine("GetValue<string> is an IGetValue<object>");
}
else
{
Console.WriteLine("GetValue<string> is not an IGetValue<object>");
}
//This doesn't work!!! Why????
if (GetInt is IGetValue<object>)
{
Console.WriteLine("GetValue<int> is an IGetValue<object>");
}
else
{
Console.WriteLine("GetValue<int> is not an IGetValue<object>");
}
Console.ReadKey();
}
}
Edit:
I realize what I'm trying to accomplish here seems vague, but this is part of a larger design whose explanation would be too verbose. What I need is to have all of my IGetValue<T>s to share a common type or interface with a property named "Value" that returns an object. Why is the verbose part.
It doesn't work because generic variance doesn't apply to value types... they have different representations, whereas variance with reference types can happen without the CLR having to perform any conversions.
So for example, you can treat an IEnumerable<string> as an IEnumerable<object>, but you can't treat an IEnumerable<int> as an IEnumerable<object>.
I ended up solving my immediate need by creating a non-generic IGetValue interface and implementing it explicitly in the class. Here's the solution:
public interface IGetValue
{
object Value
{
get;
}
}
public interface IGetValue<out T>
{
T Value
{
get;
}
}
public class GetValue<T> : IGetValue<T>, IGetValue
{
public GetValue(T value)
{
_value = value;
}
private T _value;
public T Value
{
get { return _value; }
}
object IGetValue.Value
{
get { return _value; }
}
}
class Program
{
static void Main(string[] args)
{
IGetValue<string> GetString = new GetValue<string>("Hello");
IGetValue<int> GetInt = new GetValue<int>(21);
if (GetString is IGetValue)
{
Console.WriteLine("GetValue<string> is an IGetValue");
}
else
{
Console.WriteLine("GetValue<string> is not an IGetValue");
}
if (GetInt is IGetValue)
{
Console.WriteLine("GetValue<int> is an IGetValue");
}
else
{
Console.WriteLine("GetValue<int> is not an IGetValue");
}
Console.ReadKey();
}
}