I have two List<> with the same field that I need to edit. How to write a common function for these lists?
public List<?> CutField(List<?> list)
{
foreach(var element in list)
{
element.Field = // ;
}
return List<?>;
}
Best way would be using generics:
public List<T> CutField<T>(List<T> list) where T : MyInterface
{
foreach(T element in list)
{
element.Field = // ;
}
return list;
}
With
public interface MyInterface
{
object Field { get; set; } // or whatever datatype you need for the field
}
Of course all the possible types within your list should implement that interface.
As an aside you can also omit the return-type from CutField, as you´re already modifying the list passed as parameter.
Related
I got a problem in C#, giving me an error 'The type arguments for method cannot be inferred from the usage'. Seems that the compiler cannot determine the correct interface, if I derive a generic list from a non-generic one:
Code:
public class SpecialItem : BaseItem
{
public string Title { get; set; }
}
public class BaseItem
{
public string Name { get; set; }
}
public class GenericList<T> : NongenericBaseList, IEnumerable<T>
where T: BaseItem
{
public new T this[int index]
{
get { return _items[index] as T; }
}
public new IEnumerator<T> GetEnumerator()
{
var iter = _items.GetEnumerator();
while (iter.MoveNext())
{
yield return iter.Current as T;
}
}
}
public class NongenericBaseList : IEnumerable<BaseItem>
{
protected List<BaseItem> _items;
public BaseItem this[int index]
{
get { return _items[index]; }
}
public IEnumerator<BaseItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Usage:
var genericList = new GenericList<SpecialItem>();
foreach (var item in genericList) // Uses IEnmerable<SpecialItem>, OK!
{
Console.WriteLine(item.Title);
}
var l = genericList.ToList(); // ERROR!
The ForEarch gets the correct Enumerator (SpecialItem), but the lambda does not know what to use (IEnumerable<BaseItem> or IEnumerable<SpecialItem>).
What to do? How can I set IEnumerable<SpecialItem> as 'default' interface? I dont want to explicetly code the type all the time like this:
var l = genericList.ToList<SpecialItem>();
First of all: kudos for providing a self-contained example!
You cannot specify a 'default' interface for type inference. The argument type for ToList<T> cannot be resolved because it is ambiguous, the type implements both IEnumerable<BaseItem> and IEnumerable<SpecialItem>, and both versions are applicable.
Is there a possibility to remove the class NongenericBaseList completely, and use the GenericList<T>instead? That would solve your problem; you can use GenericList<BaseItem> instead of NongenericBaseList
Another option is to reverse the inheritance; make NongenericBaseList empty and deriving from GenericList<BaseItem>.
Thanks to Sriram Sakthivel, he guided me to a solution with a very small overhead. To make things clear I wanted to make sure that:
Both lists, the generic and nongeneric one must be the same object. Therefore I have to derive, not packing in a wrapper.
Both lists must support access via loops (ForEach) and lambdas / extension methods without the need to explicitly typing the class name.
They have to implement IList<T>, so T out is not an option.
In short, the following code must compile without errors:
// Generic
var genericList = new GenericList<SpecialItem>();
foreach (var item in genericList)
{
Console.WriteLine(item.Title);
}
var l = genericList.ToList();
// Nongeneric
var nongenericList = genericList as NongenericBaseList;
foreach (var item in nongenericList)
{
Console.WriteLine(item.Name);
}
var nl = nongenericList.ToList();
I came to the conclusion, that this is not possible with the upper code (correct me if that is not true!). The loops are working fine, but either the generic or the nongeneric list does not work with .ToList() or other extension methods, because the compiler cannot inferre the type.
Now I used Sriram Sakthivel tipp, implementing only IEnumerable without <T>. But that allone would make it impossible to use extension methods at all even if you explicitely write the type.
I simply added a property, casting the collection:
public class NongenericBaseList : IEnumerable // Without the T!
{
protected List<BaseItem> _items;
// The property
public IEnumerable<BaseItem> L
{
get { return this as IEnumerable<BaseItem>; }
}
public BaseItem this[int index]
{
get { return _items[index]; }
}
public IEnumerator<BaseItem> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now I can type:
var nl = nongenericList.L.ToList();
Any better solution would be appreciated!
I have a List<T> variable where T is not known at compile time. I need to access the value property on type T like this
foreach(var item in items) // items is List<T>
{
item.value // this won't compile because T is unknown
}
I know that <T> in my case will have the value property. How can I access it?
If you KNOW that every T has VALUE you can use dynamic instead of var
foreach(dynamic item in items) //items is List<T>
{
item.VALUE
}
As already answered the correct way is to create an interface that implements the Value prop.
However you have commented that you have no control over classes you will need to do this another way.
One way would be reflection, I'm assuming your property name is VALUE, (case sensitive)
PropertyInfo pi = typeof(T).GetProperty("VALUE");
object value = pi == null ? null pi.GetValue(item,null);
You could cache the reflection call into a static generic class that creates a static field the first time it is used.
Alternatively you could use a static generic helper class with field and a helper method.
public static class ValueHelper<T> {
public static Func<T,object> ValueFunction;
public static object GetValue(T item) {
var function = ValueFunction;
return function == null ? null : function(item);
}
}
}
Then somewhere in your code, where you know T, eg you want to setup for MyClass
ValueHelper<MyClass>.ValueFunction = x => x.Value;
Then your list code becomes
foreach(var item in items)
{
value = ValueHelper<T>.GetValue(item);
}
If you have a control over T classes, you can introduce an interface with Value property and make every T class implement this interface. In that case you can enumerate list values like this:
foreach(IMyInterface item in items)
{
var someVar = item.VALUE;
//you know that item does have VALUE property and the type of that property as declared in interface
}
UPD. It works even if your T classes have different properties:
interface IMyInterface
{
string VALUE{get;set;}
}
class A : IMyInterface
{
public int Aprop{get;set;}
public string VALUE{get;set;}
}
class B : IMyInterface
{
public int Bprop{get;set;}
public string VALUE{get;set;}
}
If T types are known in advance then you can do this (not the best approach but those are already explained in other answers):
foreach(var item in List<T>)
{
if (item.GetType().Equals(typeof(fooClassA)))
{
ret = (item as fooClassA).VALUE_A;
}
if (item.GetType().Equals(typeof(fooClassB)))
{
ret = (item as fooClassB).VALUE_B;
}
....
}
I have class called GroupItem, i can store any type here say int, string, decimal, datetime etc.., Then, i have GroupItems which will store any groupItem. I'm using an arraylist to store all the groupItem.
public class GroupItem<T>
{
private string heading;
private List<T> items = new List<T>();
public GroupItem() { }
public string Heading
{
get { return heading; }
set { heading = value; }
}
public List<T> Items
{
get { return items; }
set { items = value; }
}
public void Add(T value)
{
this.items.Add(value);
}
public T this[int index]
{
get
{
return this.items[index];
}
}
}
public class GroupItems
{
private string groupName;
private List<object> items = new List<object>();
public string GroupName
{
get { return groupName; }
set { groupName = value; }
}
public GroupItems() { }
public void Add(object value)
{
this.items.Add(value);
}
public object this[int index]
{
get
{
return this.items[index];
}
}
}
I want to retrieve from GroupItems. How i can get generic item's values in groupItems?
I'm now inserting two items, datetime and int to groupitems. Now i want to retrieve groupitems[2] value but how i can convert this to groupItem without knowing what it is. Even we may get its genericarguments by getType().getGenericarguments()[0]. But how i can create an instance based upon that.
If the list is storing heterogeneous items, then I would suggest you need a common non-generic interface or base-class. So, say we have
interface IGroupItem {
// the non-generic members, and maybe
// "object Value {get;}" etc, and maybe
// "Type ItemTypr {get;}"
}
You would then have:
class GroupItem<T> : IGroupItem {...}
an you would then use
List<IGroupItem> ...
instead of ArrayList, or, franky, in place of GroupItems {...}
What I'd do is create a generic collection such as:
public class GroupItems<T> : List<GroupItem<T>>
{
}
If you need to extend the basic functionality of a list, you could also extend Collection<T> and override the methods you need:
public class GroupItems<T> : Collection<GroupItem<T>>
{
protected override void InsertItem(int index, T item)
{
// your custom code here
// ...
// and the actual insertion
base.InsertItem(index, item);
}
}
How about just replacing your GroupItems class with List<GroupItem<T>> ?
Depending on what you do with GroupItem you should either inherit from List/Collection as was offered by other or use a generic collection inside your class
e.g.
class GroupItem<T>
{
private List<T> items = new List<T>();
public void Add(T value)
{
items.Add(value);
}
public T Get()
{
//replace with some logic to detemine what to get
return items.First();
}
}
There are two situations that could be covered by your question:
You want to simply store a collection of GroupItem's of type T in the class GroupItems.
You want to store a collection of generic GroupItem's of any type in the class GroupItems. To better clarify, I mean that you could store GroupItem<DateTime> or GroupItem<int> in the same GroupItems class.
Here are some ways of going about storing and retrieving for both scenarios:
Same Type
public class GroupItem<T>
{
// ... Code for GroupItem<T>
}
public class GroupItems<T>
{
private List<GroupItem<T>> mItems = new List<GroupItem<T>>();
public void Add(T item)
{
mItems.Add(item);
}
public T GetItem(int index)
{
return mItems[index];
}
}
Here you will build a collections that contain GroupItem's of the same time, so a collection of GroupItem<DateTime> for example. All the items will be of the same type.
Generic Type
public interface IGroupItem
{
// ... Common GroupItem properties and methods
}
public class GroupItem<T>
{
// ... Code for GroupItem<T>
}
public class GroupItems
{
private List<IGroupItem> mItems = new List<IGroupItem>();
public void Add(IGroupItem item)
{
mItems.Add(item);
}
// This is a generic method to retrieve just any group item.
public IGroupItem GetItem(int index)
{
return mItems[index];
}
// This is a method that will get a group item at the specified index
// and then cast it to the specific group item type container.
public GroupItem<T> GetItem<T>(int index)
{
return (GroupItem<T>)mItems[index];
}
}
Here you will be able to build and maintain a single collection that can contain any GroupItem with any Type. So you could have a GroupItems collection that contains items of GroupItem<DateTime>, GroupItem<int>, etc.
Please note that none of these code examples take into account any erroneous circumstances.
Consider: you have a collection of items; the items may have any runtime type (string, int, etc.). Because of this, the static type of the collections items must be object.
It seems that you want to be able to retrieve items from the list with strong static typing. That's not possible without a lot of conditional logic (or reflection). For example:
object item = collection[0];
if (item is int)
//do something with an int
else if (item is string)
//do something with a string
Now suppose instead of "doing something" with the value of collection[0], we assign the value to a variable. We can do one of two things:
use the same variable for both cases, in which case the static type must be object.
use separate variables, in which case the static type will be string or int, but outside of the conditional logic, we can't know which variable holds the value of collection[0].
Neither option really solves the problem.
By creating GroupItem<T>, you add a level of indirection to this problem, but the underlying problem is still there. As an exercise, try reworking the example, but starting from "Consider: you have a collection of items; the items are of type GroupItem<T> where T may be any runtime type (string, int, etc.)."
Thanks for your inputs.
I have resolved it myself using multiple overloading methods to resolve this.
for example:
private void Print(GroupItem<string> items)
{
///custom coding
}
private void Print(GroupItem<int> items)
{
///custom coding
}
Though its not efficient enough, i want to do in this way as it was .net 2.0.
I'm now improving this in .Net 4.0 with new algorithm.
Thanks a lot for all of your helps.
I know there are very similar questions but im not sure that any of them are exactly what i need. I have 2 methods that do exactly the same thing (so i dont need to override or anything) the only difference is the parameter and return types.
public List<List<TestResult>> BatchResultsList(List<TestResult> objectList)
{
}
public List<List<ResultLinks>> BatchResultsList(List<ResultLinks> objectList)
{
}
is there a neat way of doing this that doesnt involve duplciate code (the types are used inside the method).
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
foreach(T t in objectList)
{
// do something with T.
// note that since the type of T isn't constrained, the compiler can't
// tell what properties and methods it has, so you can't do much with it
// except add it to a collection or compare it to another object.
}
}
and if you need to limit the type of T so that you'll only process specific sorts of objects, make both TestResult and ResultLinks implement an interface, say, IResult. Then:
public interface IResult
{
void DoSomething();
}
public class TestResult : IResult { ... }
public class ResultLinks : IResult { ... }
public List<List<T>> BatchResultsList<T>(List<T> objectList) where T : IResult
{
foreach(T t in objectList)
{
t.DoSomething();
// do something with T.
// note that since the type of T is constrained to types that implement
// IResult, you can access all properties and methods defined in IResult
// on the object t here
}
}
When you call the method, you can of course omit the type parameter, since it can be inferred:
List<TestResult> objectList = new List<TestResult>();
List<List<TestResult>> list = BatchResultsList(objectList);
use generic methods
public List<List<T>> BatchResultsList<T>(List<T> objectList)
{
}
when you call it for TestResult:
BatchResultsList<TestResult>(testResultList)
for ResultLinks:
BatchResultsList<ResultLinks>(resultLinksList)
EDIT:
I presume that because it's the same code inside you 2 methods, TestResult & ResultLinks must implement a common interface, let's call it SomeInterface & a common constructor, let's choose the parameterless one:
you would declare and use the method like this:
public List<List<T>> BatchResultsList<T>(List<T> objectList)
where T:SomeInterface, new()
{
List<List<T>> toReturn = new List<List<T>>();
//to instantiate a new T:
T t = new T();
foreach (T result in objectList)
{
//use result like a SomeInterface instance
}
//...
return toReturn;
}
what about
public List<IList> BatchResultsList(List<IList> objectList)
{
}
Generic version:
public List<List<T>> BatchResultsList<T>(List<T> objectList){}
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 { ... }
}
}