I have a couple of questions about my understanding of an area of .NET.
Please consider the following mockup:
interface IListInterface<T>
{
//brevity
}
interface IClassInterface
{
int Count { get; }
}
class A<T> : IClassInterface
{
List<IListInterface<T>> MyList = new List<IListInterface<T>>();
public virtual int Count { get { return MyList.Count; } }
public void Add(IListInterface<T> item) { MyList.Add(item); }
public IEnumerable<String> GetAllAsString(T source) { return MyList.Select(o=>o.ToString()); }
}
class B<T1, T2> : A<T1>
{
List<IListInterface<T2>> MyList = new List<IListInterface<T2>>();
public override int Count { get { return base.Count + MyList.Count; } }
public void Add(IListInterface<T2> item) { MyList.Add(item); }
public IEnumerable<String> GetAllAsString(T1 source1, T2 source2)
{
return base.GetAllAsString(source1).Union(MyList.Select(o => o.ToString()));
}
}
class C<T1, T2, T3> : B<T1, T2>
{
List<IListInterface<T3>> MyList = new List<IListInterface<T3>>();
public override int Count { get { return base.Count + MyList.Count; } }
public void Add(IListInterface<T3> item) { MyList.Add(item); }
public IEnumerable<String> GetAllAsString(T1 source1, T2 source2, T3 source3)
{
return base.GetAllAsString(source1, source2).Union(MyList.Select(o => o.ToString()));
}
}
My questions are:
What is the term used to describe what Class B and Class C are doing? Generic type overload inheritance?
There tends to be a lot of repeated code when doing writing such an object, especially when adding more methods which end up just calling its base, and adding its own information to the return. Is there a better way to go about this to allow for a more maintainable class file?
Edited to address the necessity of this method
By using this type of inheritance, one could define a single object which would constrain the requirements for data input and explain its usage.
var x = new C<String, int, DateTime>();
You now know the types which make up the object and you will get a compile-time error if you attempt to call x.GetAllAsString(0, "hello", "world");
This type of object may not work for you, and its fitness for use is not the subject of my question. My questions are about the name of this method and about code reuse in this situation.
[For brevity; for the purposes of my answer, I'm going to focus only on the 'Add' method, as the question/solution applies to your entire model]
Unfortunately, I don't believe you can simplify what you have already implemented. In effect, what you are aiming to do is to constrain a type ('C') at runtime to a set of available types, which (if it worked!) would give you a limited subset of Add/GetAllAsString methods.
So, after going through the compiler, it sounds like you're hoping to turn a single class with a single method like;
public class Base<T>
{
Add(IListInterface<T> o);
}
into a runtime object that exposes an interface like;
public class C
{
Add(IListInterface<string> o) { ... }
Add(IListInterface<DateTime> o) { ... }
Add(IListInterface<int> o) { ... }
}
But, you can't really use generics in that way. The only way to really accomplish this is to approach it the way you have; with a stack of derived types which each add another constrained method to your type.
Related
So I've been searching and searching for the solution to this problem, and I'm painfully aware that perhaps I just don't know how to ask the question in the right way to find an answer, so I'm more than happy, if there's an existing solution, to be pointed to the relevant article (or even just to get a better understanding/grasp of how to say what it is that I'm trying to find out!)
That being said, I have an abstract base class for managing / handling external, XML-based source data in generic ways and to act as the foundation for a ton of derived classes that sit on top of it and contexualize this raw data into use-specific formats.
In another class, intended to be an abstract foundation for a series of other classes whose jobs are to manage data that's stored in the first set of classes I described. In this second foundational class, have a method into which I want to be able to pass every and any possible class that is derived from my abstract base data class without that method having any foreknowledge of what the incoming class actually is (other than that it must be derived from the aforementioned archetype data classes).
This is obviously pretty confusing and is a difficult thing to try and explain/describe in words (thus my problem trying to ask the right question to find an answer) so below is a (greatly) pared-down code sample that I hope might better illustrate what I'm trying to say...
internal abstract class PrototypeDataClass
{
// intention is to hold and manage one generic record of unknown data.
protected List<KeyValuePair<string, string>> _data = new List<KeyValuePair<string,string>>();
protected PrototypeDataClass(PrototypeDataClass source) =>
this._data.AddRange(source._data.ToArray());
// Expects an XmlNode containing field data...
protected PrototypeDataClass(XmlNode source)
{
XmlNodeCollection nodes = source.GetElementsByTagName("field");
foreach (XmlNode node in nodes)
{
string key = XmlNode.Attributes["field"].Value,
value = XmlNode.InnerText;
this.Add(key,value);
}
}
public int Count => this._data.Count;
public string this[string index]
{
get {
int i = FindFieldByName(index);
if ((i<0) || (i>=Count)) throw new ArgumentOutOfRangeException();
return this[i];
}
set => this.Add(index,value);
}
protected int FindFieldByName(string fieldname)
{
int i=-1; while ((++i < Count) && !_data[i].Key.Equals(fieldname, StringComparison.InvariantCultureIgnoreCase));
return (i < Count) ? i : -1;
}
public void Add(string key, string value) =>
Add(new KeyValuePair<string,string>(key, value));
public void Add(KeyValuePair newData)
{
int i = FindFieldByName(newData.Key);
if (i<0)
this._data.Add(newData);
else
this._data[i] = newData;
}
public abstract string FormattedDisplayLine();
public static bool IsDerivedType(dynamic test) =>
IsDerivedType(test.GetType());
public static bool IsDerivedType(Type test) =>
(test == typeof(Object)) || (test is null) ? false :
(test.BaseType == typeof(PrototypeDataClass)) ? true : IsDerivedType(test.BaseType);
}
// Problem 1: I would like the WHERE constraint here to facilitate using
// only derivatives of PrototypeDataClass for T...
internal abstract class PrototypeDataGroup<T> where T : new()
{
List<T> _data = new List<T>();
protected PrototypeDataGroup()
{
// A clunky workaround to validate that the supplied generic type is
// derived from my prototype...
if (!PrototypeDataClass.IsDerivedType(typeof(T)))
throw new Exception(typeof(T).Name + " is not derived from PrototypeDataClass.");
}
protected PrototypeDataGroup(T[] sourceData)
{
// Same clunky workaround...
if (!PrototypeDataClass.IsDerivedType(typeof(T)))
throw new Exception(typeof(T).Name + " is not derived from PrototypeDataClass.");
foreach(T line in sourceData)
this.Add(line);
}
protected PrototypeDataGroup(XmlDocument doc)
{
// Same clunky workaround...
if (!PrototypeDataClass.IsDerivedType(typeof(T)))
throw new Exception(typeof(T).Name + " is not derived from PrototypeDataClass.");
XmlNodeCollection nodes = doc.GetElementsByTagName("rows");
foreach (XmlNode node in nodes)
this._data.Add(new PrototypeDataClass(node));
}
public int Count => this._data.Count;
public T this[int index] => this._data[index];
public void Add(T item) =>
this._data.Add(item);
public abstract string[] FormattedDisplayLines();
}
internal class MySpecificData : PrototypeDataClass
{
public MySpecificData() : base() { }
public MySpecificData(PrototypeDataClass source) : base(source) { }
public MySpecificData(XmlNode source) : base(source) { }
public MySpecificData(KeyValuePair data) : base() =>
this.Add(data);
public MySpecificData(string key, string value) : base() =>
this.Add(key, value);
// Code to manage / present the generic data in MySpecific ways...
public override string FormattedDisplayLine() =>
_data["specificField1"] + ": " + _data["specificField2"];
}
internal class MySpecificDataGroup : PrototypeDataGroup<MySpecificData>
{
public MySpecificDataGroup() : base() { }
public MySpecificDataGroup(XmlDocument doc) : base(doc) { }
public MySpecificDataGroup(MySpecificData[] source) : base(source) { }
// present / manage the collection in MySpecific ways
public override string[] FormattedDisplayLines()
{
List<string> lines = new List<string>();
for(int i=0; i<Count; i++)
lines.Add(new MySpecificData(this._data[i]).FormattedDisplayLine());
return lines.ToArray();
}
}
// This class's purpose is to provide the foundation for another set of
// classes that are designed to perform work using the data held in various
// derivations of PrototypeDataGroup<T>
internal abstract class SomeOtherClassFoundation
{
XmlDocument _doc;
public SomeOtherClassFoundation(XmlDocument source) =>
this._doc = source;
// Problem 2: would like to simply constrain Y here to EVERY/ANY
// possible derivation of PrototypeDataGroup, but when I try that,
// i.e. "public void DisplayDoc<Y>(string title) where Y : PrototypeDataGroup, new()"
// the compiler spits out an error that appears to demand that I
// pre-declare every individual allowable "Y" variant separately:
// "Using the generic type 'PrototypeDataGroup<T>' requires at least 1 type arguments"
// Soo: "public void DisplayDoc<Y>(string title) where Y : PrototypeDataGroup<MySpecificDataGroup>, PrototypeDataGroup<MyOtherSpecificDataGroup>, new()"
// As there could ultimately be dozens of such derived classes, having
// to maintain such a list manually is beyond daunting and seems
// absurd. Is there no way to specify:
// "where Y : PrototypeDataGroup<>, new()" (for any/all values of '<>'?)
protected void DisplayContents<Y>(string title) where Y : new()
{
// If I use "Y" here in lieu of "dynamic", the code won't even
// compile as the compiler decides that it's absolutely impossible for
// the Y type to have either the "Count" or "FormattedDisplayLines" methods.
// By using "dynamic", it at least waits until runtime to make that evaluation
// then reacts accordingly (though usually still badly)...
dynamic work = new Y();
if (work.Count > 0)
{
Console.WriteLn("Displaying " + work.Count.ToString() + " records:\r\n"+ title);
foreach (string line in work.FormattedDisplayLines())
Console.WriteLn(line);
}
}
}
internal class SomeOtherClassForMySpecificData : SomeOtherClassFoundation
{
public SomeOtherClassForMySpecificData(XmlDocument source) : base(source) { }
public Show()
{
string title = "Specific Field 1 | Specific Field 2\r\n".PadRight(80,'=');
base.DisplayContents<MySpecificData>(title);
}
}
So, in addition to the things that I've mentioned in comments above, the compiler also rejects that call to base.DisplayContents<MySpecificData>(title); with the error:
Error CS0310 'MySpecificData' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'Y' in the generic type or method 'SomeOtherClassFoundation.DisplayContents(string)'
Clearly MySpecificData HAS a public, parameterless constructor, and, while it is DERIVED from an abstract base type, it is not, itself, one...
Also, there are tons of problems with the dynamic implementation of the derived classes within the DisplayContents(string) function, from not recognizing the methods requested, to attempting to call the prototype methods instead of the overriding ones...
This has been killing me for three days now, and it's pretty obvious that stuff is happening here that I don't understand, so any pointers, insights, suggestions and/or clarifications would be greatly appreciated!
I didn't get what you actually want to do. But reading your code, I made some changes that seems can help:
Add a constraint to PrototypeDataGroup:
internal abstract class PrototypeDataGroup<T>
where T : PrototypeDataClass, new()
Add a constraint to DisplayContents method:
DisplayContents<Y,T>(string title)
where Y : PrototypeDataGroup<T>, new()
where T: PrototypeDataClass, new()
Make the call to DisplayContents method as below:
base.DisplayContents<MySpecificDataGroup, MySpecificData>(title);
I have two generic classes implementing one interface.
public interface Interface1
{
//implementation
}
public interface Interface2<T>
{
//implementation
}
class Class1<T>: Interface2<T> where T : Interface1
{
//implementation
}
class Class2<T>: Interface2<T>
{
//implementation
}
I would like to write a method that returns object of one of these classes, depending on the type T.
Interface2<T> GetObject<T>()
{
if (typeof(Interface1).IsAssignableFrom(typeof(T)))
{
//error
return new Class1<T>();
}
return new Class2<T>();
}
Implementation of Class1 must be limited to types implementing interface. Is there a way to convert type T to Interface1? Now I am obtaining error: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Class1'. There is no boxing conversion or type parameter conversion from 'T' to 'Test.Interface1'.
Full reflection would be:
return (Interface2<T>)Activator.CreateInstance(typeof(Class1<>).MakeGenericType(typeof(T)));
but it is slow (slow compared to doing a new Foo())... I don't find any other way. Note that you are already going partially in the reflection direction (the IsAssignableFrom)
Mmmh using the "caching" of static classes, we can cheat a little... We can produce at runtime the exact code needed for creating a new Class1<T> and cache it.
First version
static class Maker<T>
{
public static Func<Interface2<T>> Func { get; private set; }
public static Interface2<T> New()
{
if (Func == null)
{
Func = Expression.Lambda<Func<Interface2<T>>>(Expression.New(typeof(Class1<>).MakeGenericType(typeof(T)))).Compile();
}
return Func();
}
}
I use an expression tree that does the new Class1<T>. Then:
static Interface2<T> GetObject<T>()
{
if (typeof(Interface1).IsAssignableFrom(typeof(T)))
{
return Maker<T>.New();
}
return new Class2<T>();
}
But still we can do something more. Given a type T, the result of the if in GetObject() can be precalculated and cached. We move the whole GetObject() inside the expression tree.
static class Maker2<T>
{
public static Func<Interface2<T>> Func { get; private set; }
public static Interface2<T> New()
{
if (Func == null)
{
if (typeof(Interface1).IsAssignableFrom(typeof(T)))
{
Func = Expression.Lambda<Func<Interface2<T>>>(Expression.New(typeof(Class1<>).MakeGenericType(typeof(T)))).Compile();
}
else
{
Func = Expression.Lambda<Func<Interface2<T>>>(Expression.New(typeof(Class2<>).MakeGenericType(typeof(T)))).Compile();
}
}
return Func();
}
}
and then
static Interface2<T> GetObject2<T>()
{
return Maker2<T>.New();
}
The solution that uses an expression tree is very slow the first time it is used for each type T, because it has to produce the expression tree and compile it, but then it becomes very fast. This compared to the version that uses the Activator.CreateInstance that is slow every time :-)
I have taken the following class from another SO question:
public class Range<T> where T : IComparable<T>
{
public T Minimum { get; set; }
public T Maximum { get; set; }
public override string ToString() { return String.Format("[{0} - {1}]", Minimum, Maximum); }
public Boolean IsValid() { return Minimum.CompareTo(Maximum) <= 0; }
public Boolean ContainsValue(T value)
{
return (Minimum.CompareTo(value) <= 0) && (value.CompareTo(Maximum) <= 0);
}
}
I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
public class Ranges<T> where T : Range<T>
{
private List<Range<T>> rangelist;
public void add(Range<T> range)
{
rangelist.Add(range);
}
public Boolean ContainsValue(T value)
{
foreach (Range<T> range in rangelist)
{
if (range.ContainsValue(value)) return true;
}
return false;
}
}
However, i am getting the error The type 'T' cannot be used as type parameter 'T' in the generic type or method 'Range<T>'. There is no implicit reference conversion from 'T' to 'System.IComparable<T>'.
What exactly is going wrong here?
You don't seem to need the constraint where T : Range<T>
Just repeat the comparable constraint:
public class Ranges<T> where T : IComparable<T>
{
}
If you rewrite your second class slightly, you'll see why:
public class Ranges<U> where U : Range<U>
{
private List<Range<U>> rangelist;
public void add(Range<U> range)
{
rangelist.Add(range);
}
...
}
The error is telling you the compiler does not know if U is convertible to IComparable<U>, which is apparent from the declaration of Ranges<U> and Range<T> (Range<T> does not implement any interfaces).
More importantly, you have a recursing generic argument!
If U is Range<U>, then your class looks like Ranges<Range<T>> where T is U, and so on and so forth.
From what I can tell, you're not looking to write:
Ranges<Range<int>> x = ...;
But rather:
Ranges<int> x = ...;
Which would mean:
public class Ranges<T> where T : IComparable<T>
{
private List<Range<T>> rangelist;
...
You don't need new classes for that, use linq.
list1.All(x=>list2.Any(y=>y == x))
UPDATE: You are saying : I would like, however, to create another class that contains many instances of this class, and can execute a foreach loop on them all, returning true if the number passed is contained in any one of the ranges:
So effectively you have list of lists. Or more generally IEnumerable of IEnumerables.
There is enough standard generic data structures to handle this scenario
public static class ListOfListExtention {
public static bool ContainAny( this List<List<int>> lists, int number ) {
return lists.Any(l=>l.Any(x=>x == number))
}
}
Which can be rewritten in more generic way using IComparable interface
public static class ListOfListExtention {
public static bool ContainAny<T>
(this List<List<int>> lists, int value ) where T : IComparable<T> {
return lists.Any(l=>l.Any(x=>x == value))
}
}
So to compare with accepted answer, why wrap List in new class if you can just have one extension method.
I am having some troubles with generics and inheritance. I have an abstract class called CriteriaBase whose job it is to determine if an entity T matches the criteria defined in any sub-classes. The sub-classes have to implement a method which returns a Func representing the criteria. The problem arises when I try to use generics for the Func. Hopefully some code will illustrate my problem.
public abstract class CriteriaBase<T, U>
where T : ICrossoverable
where U : IChromosome
{
protected abstract Func<U, bool> Criteria { get; }
//some code removed for brevity
private int GetNumberOfCriteriaMatches(T season)
{
//1. works
//Func<IChromosome, bool> predicate = c => c.Genes == null;
//return season.Chromosomes.Count(predicate);
//2. doesn't work - The type arguments for method 'int
//System.Linq.Enumerable.Count<TSource>(this IEnumerable<TSource>,
//Func<TSource, bool>)'
//cannot be inferred from the usage. Try specifying the type arguments
//explicitly.
return season.Chromosomes.Count(Criteria);
}
}
My intention is that the CriteriaBase class should be generic and completely reusable.
An example sub-class:
public class TopTeamsPlayingEachOtherCriteria : CriteriaBase<Season, MatchDay>
{
//some code removed for brevity
protected override Func<MatchDay, bool> Criteria
{
get { return matchDay =>
matchDay.Fixtures.Count(
fixture =>
fixture.HomeTeam.TableGrouping.Ordering == 1
&& fixture.AwayTeam.TableGrouping.Ordering == 1) > 1; }
}
}
The problem is in the GetNumberOfCriteriaMatches() method. Option 2 is how I originally wrote the code but I get the compile error as listed. If I use option 1 then the code compiles but it means that when I override Criteria in the sub-class, I have to use IChromosome instead of MatchDay which doesn't work (I need to access specific features of a MatchDay). In my simple mind, options 1 and 2 are equivalent. Option 2 simply replaces IChromosome with a generic type U which is restricted to a class that implements IChromosome.
Is what I'm trying to achieve possible? If so, what am I missing/misunderstanding? If not, how should I approach this problem?
For completeness (included at the end as I'm not sure how much it helps with the question), here are the two entities that I'm currently using for T (Season) and U (MatchDay).
public class Season : ICrossoverable
{
private readonly IEnumerable<MatchDay> _matchDays;
public Season(IEnumerable<MatchDay> matchDays)
{
_matchDays = matchDays;
}
public IEnumerable<MatchDay> MatchDays
{
get { return _matchDays; }
}
//ICrossoverable implementation
public IEnumerable<IChromosome> Chromosomes
{
get { return _matchDays; }
}
}
public class MatchDay : IChromosome
{
private readonly int _week;
private readonly List<Fixture> _fixtures;
public MatchDay(int week, List<Fixture> fixtures)
{
_week = week;
_fixtures = fixtures;
}
//some code removed for brevity
public IEnumerable<Fixture> Fixtures
{
get { return _fixtures; }
}
//IChromosome implementation
public IEnumerable<IGene> Genes
{
get { return Fixtures; }
}
}
Well this is the problem:
public IEnumerable<IChromosome> Chromosomes
You're only declaring that you're returning a sequence of IChromosome values. Your criterion expects MatchDay values. You happen to know that it's actually returning a sequence of MatchDay values, but the compiler doesn't.
You could use Cast<> to check this at execution time:
return season.Chromosomes.Cast<U>().Count(Criteria);
... or you could change Chromosomes to return an IEnumerable<MatchDay>. Unfortunately we can't really tell whether that's a valid answer or not as we don't know how ICrossoverable is declared. Perhaps you should make ICrossoverable generic in the element type?
You should use keyword in before U in CriteriaBase definition. Something like this:
public abstract class CriteriaBase<T, in U>
where T : ICrossoverable
where U : IChromosome
Update. It will not work.
Try to specify type explicitly
private int GetNumberOfCriteriaMatches(T season)
{
....
return season.Chromosomes.Count<IChromosome>(Criteria);
}
I have this code
public interface IConsumable<T> {
void Consume(T item);
}
public interface IProducer<T> {
IConsumable<T> Consumer { get; set; }
void Produce();
}
public class MyClass : MyType,
IConsumable<ISpecifcItem>
{
public void Consume(ISpecificItem item) { ... }
}
public class MySpecificItemProducer
: IProducer<ISpecificItem> {
public IConsumable<ISpecificItem> Consumer { get; set; }
public void Produce() {
ISpecificItem myItem = new MyVerySpecificItem();
Consumer.Consume(myItem);
}
}
Then I'm having a controller that takes any MyType, discovers all types of IConsumable<> that it implements and gets the type of the generic type parameter. With this list of types it discovers all producers that implement IProducer<TParam>. That's not difficult:
var consumerTypes =
myType.GetType().GetInterfaces()
.Where(x => x.IsGenericType)
.Where(x => x.GetGenericTypeDefinition() ==
typeof(IConsumable<>));
if (consumerTypes.Any()) {
var instanceTypes = consumerTypes
.Select(x => x.GetGenericArguments().First())
.Select(x => typeof(IProducer<>).MakeGenericType(x));
// for each of those types discover classes where
// it assignable from
// and instantiate the class using the Activator
}
But the problem is, how do I set the Consumer property of the producer? The producer instance is an object to me, I can't cast it to an IProducer<T>, because I can't use T like a variable.
I can do it with reflection producerInstance.GetType().GetProperty("Consumer").SetValue(producerInstance, consumerInstance, null); but I wanted to know if there's another way?
Interestingly, this failed at runtime:
MyClass consumerInstance;
dynamic test = producerInstance;
test.Consumer = consumerInstance;
It complained that the type of consumerInstance was incompatible to the type of the property.
EDIT: The dynamic example worked only when consumerInstance was also a dynamic, e.g.:
dynamic testC = consumerInstance;
dynamic testP = producerInstance;
testP.Consumer = testC;
Unfortunately, without refactoring the code you provided, you cannot solve the problem without more reflection (as you have done). However, you could use reflection before you set the consumer property if it makes it more readable for you.
var method = GetType().GetMethod("Process");
var genericType = interfaceType.GetGenericArguments().First();
var invocable = method.MakeGenericMethod(genericType);
invocable.Invoke(this, new object[] { producer, consumer });
public void Process<T>(IProducer<T> producer, IConsumable<T> consumer)
{
producer.Consumer = consumer;
}
Are you giving >1 IConsumable to MyType and just altering the generic type argument? I assume you are because you get a list of those interfaces. I don't know where you get your producers from, but the only way to not use reflection is to stay out of it. You could consider forcing each 'MyType' to provide a method that would 'setup' a list of producers (MyType internally would know all of it's own consumable types). Depending on where you pull the producers from (internal to MyType or external) you may have to do the following:
public interface IProducer { }
public interface IProducer<T> : IProducer
{
IConsumable<T> Consumer { get; set; }
void Produce();
}
public interface IConsumableProvider
{
void SetupProducers(params IProducer[] producers);
}
public class MyType :
IConsumable<int>,
IConsumable<double>,
IConsumableProvider
{
public void Consume(int item)
{
throw new NotImplementedException();
}
public void Consume(double item)
{
throw new NotImplementedException();
}
public void SetupProducers(params IProducer[] producers)
{
(producers[0] as IProducer<int>).Consumer = (this as IConsumable<int>);
(producers[1] as IProducer<double>).Consumer = (this as IConsumable<double>);
}
}
I'm not in love with the solution, but I feel an optimal solution would require more information about your current code base - else I would give an answer too divergent to what you already have.