I have an object with the following:
public class ExpenseFilters<T> {
public ExpenseFilterType Type {get;set;}
public T Value {get;set;}
}
T can be a string, int, decimal in this case.
I want to create a method that accepts a generic list of ExpenseFilters:
public void DoSomething(List<ExpenseFilters<T>> filterList) {}
Is this possible somehow?
EDIT: Apologies as I wasn't being clear enough.
I want the List of ExpenseFilters to not be constrained to one generic type.
For example, the list should contain
ExpenseFilters<int>
as well as
ExpenseFilters<string>
Is this possible?
Make the method generic:
public void DoSomething<T>(List<ExpenseFilters<T>> filterList) { }
When you use this method, the type parameter T can usually be inferred by the compiler, so you don't even need to specify it:
List<ExpenseFilters<int>> list = new List<ExpenseFilters<int>>();
DoSomething(list);
Edit
Turns out it's not what you wanted to do.
It's not possible to do it with generics. The closest thing you might do is to create a non-generic interface or base class implemented/inherited by the generic one.
public interface IExpenseFilters
{
ExpenseFilterType Type { get; set; }
object Value { get; set; }
}
public class ExpenseFilters<T> : IExpenseFilters
{
public ExpenseFilterType Type { get; set; }
public T Value { get; set; }
object IExpenseFilters.Value
{
get { return Value; }
set
{
if (!(value is T))
throw new ArgumentException("Incorrect type", "value");
Value = (T)value;
}
}
}
Related
This question already has answers here:
Generic list of generic objects
(3 answers)
Closed 4 years ago.
I have an object that I want to put into a List or Collection. Is there a way to do that without having the T specified?
I want to do something like this: List<CommonProperty<T>>
Here's the object for reference:
internal class CommonProperty<T>
{
public string Name { get; set; }
public PropType Type { get; set; }
public List<T> PossibleValues { get; set; }
private T _value;
public T Value
{
get { return _value; }
set
{
if (!_value.Equals(value))
{
_value = value;
}
}
}
}
No, you can't use open generic types like that.
You could have a List<CommonProperty<T>> within a context where T is already a type parameter:
public class Foo<T>
{
static void Bar()
{
// This is fine, but is not what you're looking for - it uses
// the type parameter T as the type argument
List<CommonProperty<T>> list = new List<CommonProperty<T>>();
}
}
Typically the solution here is to have a non-generic base class or interface which the generic class or interface derives from:
// Consider making it abstract
internal class CommonProperty
{
public string Name { get; set; }
public PropType Type { get; set; }
}
internal class CommonProperty<T> : CommonProperty
{
public List<T> PossibleValues { get; set; }
private T _value;
public T Value
{
get => _value;
set
{
// TODO: Is this really necessary?
if (!_value.Equals(value))
{
_value = value;
}
}
}
}
You can then create a List<CommonProperty>... although be aware that it's entirely possible that you could end up with an element which wasn't a CommonProperty<T> at all that way.
From the List<CommonProperty> you'd be able to retrieve the names and types of all the properties - but the values wouldn't be available without casting to the specific type. You could have an abstract object Value { get; set; } property in the base class, which was then overridden in the derived class, potentially - but it's not clear whether that's necessary or helpful in your use case.
I think the closest you can get is to define an interface to match an un-typed (specific) CommonProperty, using Object instead of the T. Then have your CommonProperty<T> implement that interface. Now you can use the interface with your list.
But this isn't great. You'll lose a lot of nice type checking, and have to do more casting. If this is the primary way you'll use these objects, there's not much point to having a generic class at all anymore.
It is not possible to put a mixture of generics instantiated with different type arguments into the same collection. Such collection would not be useful anyway, because the caller would be expected to supply T for each item at compile time.
Suppose you could do what you want, i.e.
// imagine that you could do this
List<CommonProperty<T>> mixedList = GetAllProperties();
You would be forced to supply T once you start using items from that list, i.e.
foreach (CommonProperty<T> prop in mixedList) {
... // ^^^
... // Here you would need to specify T, but you don't know which one
}
In other words, such list would be unusable.
A list of properties of a specific type, on the other hand, would be useful:
List<CommonProperty<string>> stringPropList = GetPropertiesOfType<string>();
foreach (CommonProperty<string> prop in stringPropList ) {
...
}
Therefore, one solution to your problem would be building GetPropertiesOfType<T> method returning List<CommonProperty<T>> bound to type T from the caller.
An alternative approach would be to make CommonProperty non-generic, and let the caller check the type at runtime:
internal class CommonProperty {
public string Name { get; set; }
public PropType Type { get; set; }
public List<T> GetPossibleValues<T> { get; set; }
private object _value;
public T GetValue<T>() {
return (T)_value;
}
public void SetValue<T>(T val) {
_value = val;
}
}
Say for example I have this base class
class Mangler<TInput, TOutput>
{
}
And then I make a couple of derived classes
class StringToBytesMangler : Mangler<string, byte[]>
{
}
class IntToGuidMangler : Mangler<int, Guid>
{
}
How do I store a collection of Mangler<TInput, TOutput> where TInput and TOutput may be different at any given time?
i.e.
List<Mangler<?, ?>> list = new List<Mangler<?, ?>>();
list.Add(new StringToBytesMangler());
list.Add(new IntToGuidMangler());
Is this possible?
You need a non-generic Mangler base class.
List<Mangler> list = new List<Mangler>();
list.Add(new StringToBytesMangler());
list.Add(new IntToGuidMangler());
Of course, this means you also need to have non-generic versions of the methods that depend on TInput or TOutput.
If I understood the question correctly, this is not possible the way you tried it. The types StringToBytesMangler and IntToGuidMangler do not derive from the same type. You could introduce a shared base type, but I recommend reconsidering the design - even if they could be stored in the same collection, they would syntactically have nothing in common (at least it isn't shown in the question).
The whole idea behind generics is to have generic code so type of that class can be treated the same. From what you have posted, it is not easy to see what generic code you have.
Below I have a class that has some generic code:
class Mangler<TInput, TOutput>
where TInput: ITInput
where TOutput: ITOutput {
public TInput Input { get; set; }
public TOutput Output { get; set; }
public bool IsInputAGuid() {
if (Guid.Parse(this.Input.SomeThing) == this.Output.SomeGuid ) {
return true;
}
return false;
}
}
You can see in the above class, when it parses a string to a Guid from this.Input.Something and then it performs == on it with this.Ouput.SomeGuid, the compiler is happy because we have made the constraint that TInput must implement the interface ITInput so the compiler knows this line will work and Input will have Something as a string property:
Guid.Parse(this.Input.SomeThing)
The compiler does not care what the concrete type is so long as Something is available. It is the same idea for TOuput but the compiler expects that it implements ITOutput so it expects a Guid in SomeGuid. This is why the compiler is happy to parse a string to a guid and then perform the == operator on it with another thing which is also a Guid.
Here are the interfaces and some classes which implement them:
internal interface ITInput {
string SomeThing { get; set; }
}
internal interface ITOutput {
Guid SomeGuid { get; set; }
}
internal class AnotherInput : ITInput {
public string SomeThing { get; set; }
}
internal class SomeInput : ITInput {
public string SomeThing { get; set; }
}
internal class SomeOutput : ITOutput {
public Guid SomeGuid { get; set; }
}
internal class SomeOtherOutput : ITOutput {
public Guid SomeGuid { get; set; }
}
Finally, here is the usage where we can treat these generically:
var manglers = new List<Mangler<ITInput, ITOutput>>();
manglers.Add( new Mangler<ITInput, ITOutput>
{ Input = new SomeInput(), Output = new SomeOutput() } );
manglers.Add( new Mangler<ITInput, ITOutput>
{ Input = new AnotherInput(), Output = new SomeOutput() } );
foreach( var thisMangler in manglers ) {
var input = thisMangler.Input;
var output = thisMangler.Output;
var success = thisMangler.IsInputAGuid();
}
You can see in the foreach regardless of the concrete type, we can call Input, Output and IsInputAGuid() on all of them.
So in your code find what code is generic and then apply the above technique to it. You can either use interfaces or a base class for your constraints.
In Winform application I have a class with 2 properties and I want the user to be able to choose the type of those properties.
This is what I made so far:
Class with the properties:
static public class DataGridColumnData
{
public static object SearchColumn { get; set; }
public static object ResultColumn { get; set; }
}
And the user can choose the type of the properties using a Combobox with DropDownList Style which has values like
System.String
System.Double
System.Int32
System.Boolean
System.DateTime
Is there a way to make those properties to be types the ones that user chooses?
You can make your class generic:
static public class DataGridColumnData<T>
{
public static T SearchColumn { get; set; }
public static T ResultColumn { get; set; }
}
Then, in your code, you can create a class of the desired type:
object myDataGridColumnData;
if (userSelection == "String") {
myDataGridColumnData = new DataGridColumnData<string>();
} else if (userSelection == "Double") {
myDataGridColumnData = new DataGridColumnData<double>();
} ...
Note that, technically, DataGridColumnData<string> is a completely different type than DataGridColumnData<int>, so object is the only common supertype. Thus, to be able to access the values of myDataGridColumnData in code, you might need to use a dynamic variable or (prefered) use some common interface or base class that returns the values typed as objects.
There are ways to make the properties strongly typed in runtime using generics, but I am not sure how useful it is. Here is a solution either way:
Create an interface that is not strongly typed to facilitate interaction with the object:
public interface IDataGridColumnData
{
object SearchColumnAsObject { get; set; }
object ResultColumnAsObject { get; set; }
}
Create generic class that allows for the creation of strongly typed versions at runtime (and in code as well, of course), and that implements the interface:
public class DataGridColumnData<TSearch, TResult> : IDataGridColumnData
{
public TSearch SearchColumn { get; set; }
public static TResult ResultColumn { get; set; }
public object SearchColumnAsObject
{
get { return SearchColumn; }
set { SearchColumn = (TSearch)value; }
}
public object ResultColumnAsObject
{
get { return ResultColumn; }
set { ResultColumn = (TResult)value; }
}
}
Create a factory method that will manufacture strongly typed versions of the class, returning it as the object-typed interface:
private static IDataGridColumnData GetDataGridColumnData(
Type searchType, Type resultType)
{
var typedColumnDataType = typeof(DataGridColumnData<,>)
.MakeGenericType(new[] { searchType, resultType });
return (IDataGridColumnData)Activator.CreateInstance(typedColumnDataType);
}
...and put it to use:
IDataGridColumnData instance = GetDataGridColumnData(
Type.GetType("System.Int32"),
Type.GetType("System.String"));
// use the properties
instance.SearchColumnAsObject = 42; // works well
instance.SearchColumnAsObject = "42"; // throws exception
No, ther is not. A class is statically compiled. No wy to change the property for a static class at runtime.
You can create a subclass nd override it, via bytecode emission, though.
You can use the is keyword
if (x.SearchColumn is Double)
{
}
See also MSDN: Is (C# Reference)
I want to have a Dictionary where the values are generic objects and will not be the same for each value int he dictionary. How can this be done, I feel like I am missing something simple.
EG
public interface IMyMainInterface
{
Dictionary<string, IMyInterface<T>> Parameters { get; }
}
public interface IMyInterface<T>
{
T Value
{
get;
set;
}
void SomeFunction();
}
Result:
dic.Add("key1", new MyVal<string>());
dic.Add("key2", new MyVal<int>());
You can't do that because T has no meaning in IMyMainInterface. If your aim is for each value to be an implementation of some IMyInterface<T> but each value could be an implementation for a different T, then you should probably declare a base interface:
public interface IMyInterface
{
void SomeFunction();
}
public interface IMyInterface<T> : IMyInterface
{
T Value { get; set; }
}
then:
public interface IMyMainInterface
{
Dictionary<string, IMyInterface> Parameters { get; }
}
EDIT: Given your updated question, it looks like this is what you're trying to do. If you want to know why you have to do this, think about how you would try to use the values in the dictionary if you were able to use your original code. Imagine:
var pair = dictionary.First();
var value = pair.Value;
What would type could value be inferred as?
If, however, each value should be of the same T, then you just need to make your other interface generic too. To make it clearer, I've renamed the type parameter to keep the Ts separate:
public interface IMyMainInterface<TFoo>
{
Dictionary<string, IMyInterface<TFoo>> Parameters { get; }
}
I have a class that stores a serialized value and a type. I want to have a property/method returning the value already casted:
public String Value { get; set; }
public Type TheType { get; set; }
public typeof(TheType) CastedValue { get { return Convert.ChangeType(Value, typeof(_Type)); }
Is this possible in C#?
It's possible if the class containing the property is generic, and you declare the property using the generic parameter:
class Foo<TValue> {
public string Value { get; set; }
public TValue TypedValue {
get {
return (TValue)Convert.ChangeType(Value, typeof(TValue));
}
}
}
An alternative would be to use a generic method instead:
class Foo {
public string Value { get; set; }
public Type TheType { get; set; }
public T CastValue<T>() {
return (T)Convert.ChangeType(Value, typeof(T));
}
}
You can also use the System.ComponentModel.TypeConverter classes to convert, since they allow a class to define it's own converter.
Edit: note that when calling the generic method, you must specify the generic type parameter, since the compiler has no way to infer it:
Foo foo = new Foo();
foo.Value = "100";
foo.Type = typeof(int);
int c = foo.CastValue<int>();
You have to know the type at compile time. If you don't know the type at compile time then you must be storing it in an object, in which case you can add the following property to the Foo class:
public object ConvertedValue {
get {
return Convert.ChangeType(Value, Type);
}
}
Properties, events, constructors etc can't be generic - only methods and types can be generic. Most of the time that's not a problem, but I agree that sometimes it's a pain. Brannon's answer gives two reasonable workarounds.
I don't believe the example you've given here is possible. The type of CastedValue has to be defined at compile time, which means it can't depend on a runtime value (the value of the TheType property).
EDIT: Brannon's solution has some good ideas for how to handle this using a generic function rather than a property.