I have a class defined with a generic:
public class GenericDataStore<T>
{
// UnderlyingDataStore is another class that manages a queue, or a linked list
private UnderlyingDataStore<T> dataQueue = new UnderlyingDataStore<T>();
public void addData(T data) { dataQueue.Add(data); }
public T getLastData() { dataQueue.getLastData(); }
}
I then have different derived classes based on this class:
public class ByteDataStore : GenericDataStore<Byte>
{
}
public class DoubleDataStore : GenericDataStore<Double>
{
}
public class PObjDataStore : GenericDataStore<PObj> // PObj is another class declared somewhere
{
}
Then, I have a "Manager" class that looks like:
public class DataManager
{
/* Here, I want to declare a 2 dim array [,] that holds pointers to the
data stores. Depending on some other variables, the array may need
to point to DoubleDataStore, ByteDataStore, etc. The following doesn't work,
since GenericDataStore must be declared with a generic type: */
GenericDataStore [,] ManagedDataStores; // Can not compile
public DataManager() {
for (int i=0; i<numStores; i++) {
for (int j=0; j<numCopies; j++) {
// objType is a utility function that we have that returns a type
if (objType(i,j) == typeof(Byte)) {
ManagedDataStores[i,j] = new ByteDataStore();
} else if (objType(i,j) == typeof(double)) {
ManagedDataStores[i,j] = new DoubleDataStore();
}
}
}
}
void Add(int id, int copyid, Byte data) {
ManagedDataStores[i,j].Add(data);
}
}
There might be other, better ways to do this. Essentially, we want to have different data stores for different object types, which can be managed by a class. We want only this 'manager' class to be exposed to the user (like an API), and no direct access to the underlying classes.
Thanks in advance.
I'm afraid that this is one of those instances where Generic's don't help you one bit. By definition, you must know the generic type at compile time, rather than runtime. For runtime type-indiference, you need to do it the old-fashioned way.
public class DataStore
{
// UnderlyingDataStore is another class that manages a queue, or a linked list
private UnderlyingDataStore dataQueue = new UnderlyingDataStore();
public void addData(object data) { dataQueue.Add(data); }
public object getLastData() { dataQueue.getLastData(); }
}
This, has the obvious drawback of boxing/unboxing- as well as the need for calling-code to know what type's it should be dealing with in order to cast.
However, you could also use the other answer, as long as you're able to cast the managedDataStore to the correct generic type.
If you want to create and initialize the double dimensional array use this:
int numStores = 2;
int numCopies = 3;
//GenericDataStore<object>[,] managedDataStores = new GenericDataStore<object>[numStores,numCopies];
Object[,] managedDataStores = new Object[numStores,numCopies];
for (int i = 0; i < numStores; i++)
{
for (int j = 0; j < numCopies; j++)
{
managedDataStores[i,j] = new GenericDataStore<object>();
}
}
I would add an interface and implement it explicitly to hide it from the class users:
internal interface GeneralDataStore
{
void addData(object data);
object getLastData();
}
public class GenericDataStore<T> : GeneralDataStore
{
// UnderlyingDataStore is another class that manages a queue, or a linked list
private UnderlyingDataStore<T> dataQueue = new UnderlyingDataStore<T>();
public void addData(T data) { dataQueue.Add(data); }
public T getLastData() { dataQueue.getLastData(); }
object GeneralDataStore.getLastData() { return getLastData(); }
void GeneralDataStore.addData(object data) { add((T)data); }
}
GeneralDataStore [,] ManagedDataStores;
This doesn't give you what you want, since it's impossible. But it give you some type safety.
Related
I have this scenario:
private MyResponse MakeTransaction<T>(T data)
{
TransactionData transactionData = new TransactionData()
{
number = data.Number
}
if(req is NewPayoutData) {
transactionData.New = data.New;
}
....
}
I call this method like this:
public MyResponse Payment(PayoutData data)
{
return MakeTransaction(data);
}
public MyResponse NewPayment(NewPayoutData data)
{
return MakeTransaction(data);
}
The problem is that 'Number' property exists in both types but the 'New' property exists only in 'NewPayment' Type.
How can I overcome this problem?
Thanks.
The best you're going to get with generics is to constrain T to be a common interface or base class that has the Number property. However this leaves out the setting of the New property which is still based on type checking. Assuming an interface it might look like:
public interface IPayout
{
int Number { get; }
}
public class PayoutData : IPayout { ... }
public class NewPayoutData : IPayout { ... }
private MyResponse MakeTransaction<T>(T data) where T: IPayout
{
TransactionData transactionData = new TransactionData
{
number = data.Number // now works
};
// type checking still required :-(
if(data is NewPayoutData)
{
transactionData.New = true;
}
...
}
The type checking sort of defeats the purpose of generics. If you only have the two types a generic method is probably not the best way to go. I'd consider method overloading instead--especially since NewPayoutData looks to just be a marker type:
private MyResponse MakeTransaction(PayoutData data)
{
TransactionData transactionData = new TransactionData
{
number = data.Number
};
...
}
private MyResponse MakeTransaction(NewPayoutData data)
{
TransactionData transactionData = new TransactionData
{
number = data.Number,
New = true
};
...
}
If they have an inheritence relationship, you could still have a single method that checks for the subclass:
public class PayoutData
{
public int Number { get; set; }
}
public class NewPayoutData : PayoutData
{
}
private MyResponse MakeTransaction(PayoutData data)
{
TransactionData transactionData = new TransactionData
{
number = data.Number
};
// type checking
if(data is NewPayoutData)
{
transactionData.New = true;
}
...
}
My preferred method would be overloading as I think it's more explicit.
You could specifically cast transactionData to the required type. Better would probably be to make helper methods that deal with (strongly typed) functionality and call those from MakeTransaction.
I'm not entirely sure of your inheritance model, nor what you actually return in MakeTransaction, so I could be off base.
I am using Google.OrTools version 7.0.
I have built a small interface in order to add constraints to a CpModel:
public interface ISatConstraintWrapper
{
IEnumerable<BoundIntegerExpression> GenerateConstraints();
void BindToModel(CpModel model);
}
The design pattern is fairly simple, here is a dummy example that sets equality to all IntVars in a list:
class MakeAllVarsEqual : ISatConstraintWrapper
{
public MakeAllVarsEqual(List<IntVar> vars)
{
_vars = vars;
}
public IEnumerable<BoundIntegerExpression> GenerateConstraints()
{
for (var i = 0; i < _vars.Count - 1; i++)
{
yield return _vars[i] == _vars[i+1];
}
}
public void BindToModel(CpModel model)
{
foreach (var constraint in GenerateConstraints())
{
model.Add(constraint);
}
}
private readonly List<IntVar> _vars;
}
Next, I would like to use my ISatConstraintWrapper but for minimize/maximize constraints.
Here is an example of what I aim to do:
class MinimizeIntExpression : ISatConstraintWrapper
{
public MinimizeIntExpression(List<IntVar> vars, List<int> coeffs)
{
_vars = vars;
_coeffs = coeffs;
}
public IEnumerable<BoundIntegerExpression> GenerateConstraints()
{
for (var i = 0; i < _vars.Count; i++)
{
yield return _vars[i]*_coeffs[i];
}
}
public void BindToModel(CpModel model)
{
model.Minimize(new SumArray(GenerateConstraints()));
}
private readonly List<IntVar> _vars;
private readonly List<int> _coeffs;
}
But I can't, since _vars[i]*_coeffs[i] returns an IntegerExpression but not a BoundIntegerExpression.
However, even if the latter represents an IntegerExpression in a domain, those two classes seems unrelated and I didn't find a way to downcast a BoundIntegerExpression to an IntegerExpression.
Of course I could make two different interfaces but it wouldn't come as handy, for instance if I want to store my constraint wrappers in a list.
Is it possible to convert a BoundIntegerExpression to an IntegerExpression? If not, how could I modify my wrapper to handle both types of constraints?
You cannot.
I suggest you read:
https://github.com/google/or-tools/blob/stable/ortools/sat/doc/channeling.md
I have interface that defines value and few operations:
public interface IValue<T>
{
T Value { get; }
void InteractionA(IValue<T> target);
void InteractionB(IValue<T> target);
bool Check(IValue<T> target);
}
Then i implement class based on that interface
public class DoubleValue : IValue<double>
{
public double Value { get; private set; }
public bool Check(IValue<double> target)
{
// ...
return false;
}
public void InteractionA(IValue<double> target)
{
// ...
}
public void InteractionB(IValue<double> target)
{
// ...
}
}
Now i want to make universal manipulator that operates on pool of values and uses generics (so i only write it once). Because of the way i want to use this class in the future it cannot be declared static. Moving generic type into methods also doesn't do any good.
The closest i could get is:
public class ValueManipulator<T>
{
public IEnumerable<IValue<T>> Pool { get; private set; }
public ValueManipulator(IEnumerable<IValue<T>> pool)
{
Pool = pool;
}
public void ManipulateA()
{
foreach (int i in Enumerable.Range(0, Pool.Count()))
{
IValue<T> firstValue = Pool.ElementAt(i);
foreach (IValue<T> secondValue in Pool.Skip(i))
{
if (firstValue.Check(secondValue))
firstValue.InteractionA(secondValue);
else
firstValue.InteractionB(secondValue);
}
}
}
public void ManipulateB()
{
// ...
}
}
Main problem with this ValueManipulator class is that i need to know T of IValue used in DoubleValue (in this case double). So it looks like this:
static void Main(string[] args)
{
ValueManipulator<double> doubleManipulator = new ValueManipulator<double>();
doubleManipulator.Manipulate(ProvideDoubles());
}
private static IEnumerable<DoubleValue> ProvideDoubles()
{
yield return new DoubleValue();
yield return new DoubleValue();
yield return new DoubleValue();
}
How do i make ValueManipulator so user does not need to know what type was used in value implementation?
Well, if your ValueManipulator<T> has no state, as appears to be your case according to your code snippets, then simply make the methods generic instead of the class, that way you can leverage type inference.
public class ValueManipulator
{
public void Manipulate<T>(IEnumerable<IValue<T>> pool)
{
foreach (int i in Enumerable.Range(0, pool.Count()))
{
IValue<T> firstValue = pool.ElementAt(i);
foreach (IValue<T> secondValue in pool.Skip(i))
{
if (firstValue.Check(secondValue))
firstValue.InteractionA(secondValue);
else
firstValue.InteractionB(secondValue);
}
}
}
}
Now you can simply do:
ValueManipulator myManipulator = new ValueManipulator();
myManipulator.Manipulate(ProvideDoubles()); //type inference will figure out T is double
If this is a valid solution then consider making ValueManipulator a static class:
ValueManipulator.Manipulate(ProvideDoubles());
P.D. Please follow advice in commentaries and change ValueType to some other name thats less confusing.
UPDATE After your latest edit to your question, where you clearly state that ValueManipulator<T> does have state, the solution seems to be implementing a static factory class:
public static class ValueManipulator
{
public static ValueManipulator<T> Create<T>(IEnumerable<IValue<T>> pool)
=> new ValueManipulator<T>(pool);
}
public class ValueManipulator<T> { ... }
And again you let type inference do its job:
var doubleManipulator = ValueManipulator.Create(ProvideDoubles());
How to define generic class for mapping muti-class?
I asked the question before,but i want like this
public class BaseRepositoryService<T1,T2,T3...Tn> where T:class
{
maplestory2Context mc = new maplestory2Context();
public T AddEntity(params object [] args)
{
for (int i = 0; i < args.Length; i++)
{
object obj = args[i];
}
}
}
but i am not sure the how many params I would use. thanks.
note:i changed my code below,but it is not convenience.
public class BaseRepositoryService<T> where T:class
{
maplestory2Context mc = new maplestory2Context();
public T AddEntity(T entity,int size)
{
if (size == 2)
{
}
return null;
}
}
public class BaseRepositoryService<T,T2>
where T : class
where T2:class
{
maplestory2Context mc = new maplestory2Context();
public T AddEntity(T entity, int size)
{
if (size == 2)
{
}
return null;
}
}
Answer to this question is you can't.
You need to define n no of classes for that even Microsoft has defined Func delegates 15 or 16 times. You can refer to msdn documentation for confirmation.
If you don't want write those classes manually you may opt for t4 templates as code generator.
I would like to be able to present a choice to the user - whether to use 16bit indices (in OpenGL) or 32bit indices. In C++, I'd probably just create an alias for int or short, but I don't seem to have the option in C#. Basically what I'm going for can be summed up in the class below:
using System;
namespace Something
{
public class Conditional
{
public Conditional(Boolean is16Bit)
{
if (is16Bit)
{
SOMETYPE is Int16
}
else
{
SOMETYPE is Int32
}
}
private List<SOMETYPE> _something;
}
}
The aliasing (if it can be done) would be vastly better - I just don't want to force anyone using this code into writing #define statements, is that possible?
Thanks
Seems like you could use a generic for this:
namespace Something
{
public class Conditional<T>
{
private List<T> _something = new List<T>();
private Conditional()
{
// prevents instantiation except through Create method
}
public Conditional<T> Create()
{
// here check if T is int or short
// if it's not, then throw an exception
return new Conditional<T>();
}
}
}
And to create one:
if (is16Bit)
return Conditional<short>.Create();
else
return Conditional<int>.Create();
You can use an interface and a factory, something like this:
public interface IConditional
{
void AddIndex(int i);
}
private class Conditional16 : IConditional
{
List<Int16> _list = new List<Int16>();
public void AddIndex(int i)
{
_list.Add((short)i);
}
}
private class Conditional32 : IConditional
{
List<Int32> _list = new List<Int32>();
public void AddIndex(int i)
{
_list.Add(i);
}
}
public static class ConditionalFactory
{
public static IConditional Create(bool is16Bit)
{
if (is16Bit)
{
return new Conditional16();
}
else
{
return new Conditional32();
}
}
}
Your code (and callers of it) can do everything against IConditional without caring which of the concrete representations it is.