Generic Dictionary with a value as a Interface with a Generic reference - c#

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; }
}

Related

Is it possible to have a collection of Object<T> classes? [duplicate]

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;
}
}

How to store a list of different generic things in C#

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.

How to pass in a list of generic Objects?

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;
}
}
}

Required property in a template type in C#

Considering a generic method, is there a possibility to set a constraint on the template type to have some specific properties?
In order to compile successfully the following code for example
public static int[] DoSomething<T> (T[] Input)
{
int[] Output = new int[Input.Length];
for (int i = 0;i < Input.Length;i++)
Output[i] = (int)Input[i].PropertyA+(int)Input[i].PropertyB;
return Output;
}
the template type needs to implement the PropertyA and PropertyB.
Is it possible somehow to set such a constraint on the template type?
EDIT:
And require in addition that PropertyA and PropertyB to be numeric types so they could be typed to int.
Thanks.
The only possibility is to define T as type derived from some well known base class or implementing well known interface:
public interface IWellKnown
{
int PropertyA { get; }
int PropertyB { get; }
}
Any your method will be:
public static int[] DoSomething<T> (T[] Input) where T : IWellKnown
{
int[] Output = new int[Input.Length];
for (int i = 0;i < Input.Length;i++)
Output[i] = Input[i].PropertyA+Input[i].PropertyB;
return Output;
}
Edit:
Creating generic method working with any numeric type but just with numeric types is imho not possible because .NET doesn't have any base type like Number. So you cannot limit generic type to numbers only. All numeric types are value types so you can do something like:
public interface IWellKnown<TData> where TData : struct
{
TData PropertyA { get; }
TData PropertyB { get; }
}
But in such case your interface will accept any value type - any custom structure, char, bool, etc.
Its not possible to create such an restriction. You should check the input at runtime and throw a helpful exception error message.
You can however do something like:
public interface IWellKnown
{
int PropertyA { get; }
int PropertyB { get; }
}
public abstract class WellKnownBase<T> : IWellKnown
{
IWellKnown.PropertyA { get { return Convert(this.PropertyA); } }
IWellKnown.PropertyB { get { return Convert(this.PropertyB); } }
public T PropertyA { get; }
public T PropertyA { get; }
protected virtual int Convert(T input) { return (int)input; }
}
Using such a base class guides the one implementing a concrete version to provide a way to cast to int. The explicit interface implementation provides access to int typed accessors while the "real" class still provides the original type.
public class WellKnownFloat : WellKnownBase<Float> {}
Would provide you with a class for float. If the type is not castable to int you can provide a custom converter:
public class WellKnownTimeSpan : WellKnownBase<TimeSpan>
{
protected override int Convert(TimeSpan input)
{
return (int)input.TotalMilliseconds;
}
}
By the way, using linq and adding the requirement to the interface you can rewrite your function to input.Select(x => x.PropertyA + x.PropertyB)).ToArray().
PS: please check the code using VisualStudio, I am just writing it out of my head without compiler support ;) There may be small compiletime errors.

Making a generic property

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.

Categories