I just have this simple generic class, which should take T and create one property. If I try to get this property and it does not exists, it should create new instance of this T type and return it. That is why I need to set new() constraint on T.
public class ExternalRepository<T> where T : class, IRepositoryable, new()
{
public IRepositoryable Value
{
get
{
if (RequestCacheManager.GetAt<T>(typeof(T).Name) == null)
RequestCacheManager.SetAt<T>(typeof(T).Name, new T());
return RequestCacheManager.GetAt<T>(typeof(T).Name);
}
}
}
And now I need to create a list of these. But it looks like it is imposible, because of the new() constraint. I'm need something like this:
public static List<ExternalRepository<T>> ExternalRepositories { get; set; } where T : class, IRepositoryable, new()
But this is not valid. Could you please help me solve this?
Thank you.
You want to put, let's say, ExternalRepository<Person> and ExternalRepository<Order> together in a list, correct?
Sadly, this can't be done explicitly. You'll have to use an interface or base class.
public interface IExternalRepository
{
// declaration of common properties and methods
}
public class ExternalRepository<T> : IExternalRepository
where T : class, IRepositoryable, new()
{
// implementation of common properties and methods
// own properties and methods
}
public static List<IExternalRepository> ExternalRepositories { get; set; }
or
public class ExternalRepository
{
// shared properties and methods
}
public class ExternalRepository<T> : ExternalRepository
where T : class, IRepositoryable, new()
{
// own properties and methods
}
public static List<ExternalRepository> ExternalRepositories { get; set; }
See also my reply to this question.
Related
I have a parent class like this:
public class WebserviceResultPerNode
{
public List<DBMappingResult> mapTable { get; set; }
public static WebserviceResultPerNode newInstanceFromError(ErrorResponse error)
{
return new WebserviceResultPerNode
{
mapTable = null,
responseCode = error.responseCode,
responseMessage = error.responseMessage
};
}
}
It have some derived classes such as below:
public class WebserviceInsertResultPerNode : WebserviceResultPerNode
{
}
Now I want to make derived classes like WebserviceInsertResultPerNode such that when I call WebserviceInsertResultPerNode.newInstanceFromError() their return type be same as derived class not parent class. Currently return type of newInstanceFromError is type of parent class, i.e. WebserviceResultPerNode.
I want to know are there any ways to override WebserviceInsertResultPerNode.newInstanceFromError such that its return type be WebserviceInsertResultPerNode but I don't need to initialize fields of parent class without the need to rewrite them.
How can I rewrite my code to achieve this goal?
You can simply achieve this by using reflection, providing child classes will always have a parameter-less constructor:
public class WebserviceResultPerNode<T> where T : WebserviceResultPerNode<T>, new()
{
public static T NewInstanceFromError(ErrorResponse error)
{
return new T() { … };
};
}
Then the descendant class will look like this:
public class MyWebServiceResult : WebserviceResultPerNode<MyWebServiceResult> { … }
However, I do strongly recommend decomposing the factory method into a separate factory class for the sake of separation of concerns.
This question already has an answer here:
Generic Type in constructor
(1 answer)
Closed 2 years ago.
I have a generic class. The constructor needs to accept an argument that is another instance of the same class. The problem is that the other instance can have a different generics type.
Looks like C# allows me to have a method with it's own generics type, but this doesn't appear allowed for the constructor.
public class MyClass<T>
{
public MyClass<T2>(MyClass<T2> parent = null)
{
}
// ... Additional stuff
}
The code above tells me T2 is undefined. It doesn't accept it as a method type.
One approach would be to add a second generic type to my class. But this is awkward and, in many cases, the argument will be null and there is not type.
Does anyone see a simple way around this?
Generic constructors aren't allowed. However, you can use a generic factory method instead.
public class MyClass<T>
{
public int Id { get; private set; }
public int? ParentId { get; private set; }
public static MyClass<T> Create(int id)
{
return Create<object>(id, null);
}
public static MyClass<T> Create<T2>(int id, MyClass<T2> parent = null)
{
var current = new MyClass<T>();
current.Id = id;
current.ParentId = parent?.Id;
return current;
}
private MyClass()
{
}
// ... Additional stuff
}
Sample use:
var intClass = MyClass<int>.Create(55);
var charClass = MyClass<char>.Create(234, intClass);
// charClass.ParentId is 55
This is only possible if you do not need to access any generic members of parent outside the factory method. If you do, you'd be better off abstracting it through a non-generic interface or base class.
You are correct. Generic constructors aren't supported.
You could probably try the following:
Create a lower level common interface
public interface IMyClass {
//...some common stuff
IMyClass Parent { get; set; }
}
And use that as the common link between the types
public class MyClass<T> : IMyClass {
public MyClass(IMyClass parent = null) {
Parent = parent;
}
public IMyClass Parent { get; set; }
// ... Additional stuff
}
I've a Generic type, which is used to give some meta data on an object to persist:
public class PersistedElementDefinition<T> where T: IPersistedObject{
List<PersistedPropertyDefinition<T>> PropertiesToPersist {get;set;}
}
public class PersistedPropertyDefinition<T> where T: IPersistedObject{
public Func<T, object> PropertyGetter{get;set;}
public Action<T, object> PropertySetter {get;set;}
}
and I've my IPersistedObject which can give his definition
public interface IPersistedObject{
PersistedElementDefinition<TypeOfTheImplementingType> Definition {get;}
}
The idea is that if I implement IPersistedObject I should implement it like this:
public class MyPersistedObject:IPersistedObject{
PersistedElementDefinition<MyPersistedObject> Definition{get;}
}
When I persist my class have the following thing:
I can't do the following:
public interface IPersistedObject<T>{
PersistedElementDefinition<T> Definition {get;}
}
because:
It would allow to have a MyPersistedObject<SomeOtherObject
At some point I receive an object, and I should be able to see if it implements the IPersistedObject and do some custom action with it.
For the 2, here is an example of what kind of issue I'm facing if I've a Generic interface:
public void Persist<T>(T objectToPersist)where T:IPersistedObject{
...
foreach(PersistedPropertyDefinition<T> property in objectToPersist.PropertiesToPersist){
object objectToSerialize = property.ObjectGetter(objectToPersist);
if(objectToSerialize is IPersistedObject<___Don't know how to put something generic here___>){
Persist((IPersistedObject<___Don't know how to put something generic here___>)objectToSerialize);
}
}
...
}
Is there a possibility in c# to declare an interface with a generic property of the implementing type?
You can use the curiously recurring template pattern to lock this down a bit further. It isn't bulletproof, but assuming you're not a masochist, and you don't mind the fact that it is theoretically possible to create nonsensical implementations of the interface that violate the invariants you are trying to guarantee, you can do this:
public interface IPersistedObject<T> where T : IPersistedObject<T>
{
PersistedElementDefinition<T> Definition {get;}
}
public class PersistedElementDefinition<T> where T: IPersistedObject<T>
{
...
}
public class MyPersistedObject : IPersistedObject<MyPersistedObject>
{
// Here, you are forced to implement a PersistedElementDefinition<MyPersistedObject>,
// which presumably is the reason behind this whole song and dance
PersistedDefinition<MyPersistedObject> Definition { get; }
}
The problem with this, as you noticed at the outset, is that you could simply define public class MyPersistedObject : IPersistedObject<MyOtherPersistedObject>, and end up breaking the contract you are trying to cobble together, which in plain words is the following:
A persisted object must have a gettable definition that is a persisted element definition of its own type
The C# type system is simply not equipped to handle this elegantly. My advice is to get out early, change to object or dynamic where possible and learn to live with the loss of certain compile time guarantees.
Assuming you're willing to sacrifice some compile time safety, you could do things like so:
class Program
{
static void Main(string[] args)
{
var mpo = new MyPersistedObject();
var ptp = mpo.Definition.PropertiesToPersist;
}
}
public class PersistedElementDefinition<T> where T : IPersistedObject
{
private readonly List<PersistedPropertyDefinition<T>> _propsToPersist = new List<PersistedPropertyDefinition<T>>();
public List<PersistedPropertyDefinition<T>> PropertiesToPersist
{
get { return _propsToPersist; }
}
}
public class PersistedPropertyDefinition<T> where T : IPersistedObject
{
public Func<T, object> PropertyGetter { get; set; }
public Action<T, object> PropertySetter { get; set; }
}
public interface IPersistedObject
{
dynamic Definition { get; }
}
public class MyPersistedObject : IPersistedObject
{
private readonly PersistedElementDefinition<MyPersistedObject> _definition = new PersistedElementDefinition<MyPersistedObject>();
public dynamic Definition { get { return _definition; } }
}
I am trying to get to grips with more complicated inheritance structures and generics and I am trying to create some architecture for a current project which is following this suit. My problem currently is I am getting this error:
Type argument 'Foo' does not inherit from or implement the constraint type 'ListBase'
public class ItemBase {}
public class ListBase<T> where T : ItemBase
{
public virtual List<T> ListExample {get; set; }
}
These are my base classes, although they probably aren't named appropriately I have just tried to show a simple example of what I am trying to achieve.
public class FooItem : ItemBase { }
public class Foo : ListBase<FooItem>
{
public override List<FooItem> ListExample { get; set;}
}
So I can then extend the initial base class for the lists and do more with it, but I want a generic way of handling all of these classes.
public class ListHandler<T> where T : ListBase<ItemBase> { }
When I try to pass Foo as T to the ListHandler I get the error mentioned, I thought that inevitably because Foo is a List<ItemBase> and FooItem is of type ItemBase I would be able to do this var handler = new ListHandler<Foo>();.
Could anybody explain why I can't do this or what I am doing wrong?
A ListBase<ItemBase> is not the same as a ListBase<FooItem>.
In particular, you can add any kind of ItemBase to a ListBase<ItemBase>.
You need to accept two generic parameters:
public class ListHandler<TList, TItem> where T : ListBase<TItem> where TItem : ItemBase { }
You need to supply the type parameter of the item type, not the list type. To clarify this, try expanding the ListHandler class to include an AddItem method which adds a ItemBase item to a ListBase instance:
// As is: Won't work, because there is no way to refer to the constructed
// specific type of ItemBase:
public class ListHandler<TList> where TList: ListBase {
public TList List { get; private set; }
public ListHandler(TList List) { this.List = List; }
public void AddItem(T???? item) { List.ListExample.Add(item); }
}
// Corrected: this will work because TItem can be used to constrain
// the constructed ListBase type as well:
public class ListHandler<TItem> where TItem : ItemBase {
public ListBase<TItem> List { get; private set; }
public ListHandler(ListBase<TItem> List) { this.List = List; }
public void AddItem(TItem item) { List.ListExample.Add(item); }
}
// And this will work just fine:
var handler = new ListHandler<FooItem>(new FooList());
I want to force subclasses to define a constant value.
Like
const string SomeConstantEverySubclassMustDefine = "abc";
I need that because I need to have it tied to the Type, rather than to the instance and you can't override static Methods/Properties iirc.
I'd really like to have a compile-time check for those constants.
Let me explain in more detail:
Some classes in our Domain-Model are special, you can take certain actions for them, depending on the type. Thus the logic is tied to the type. The action to be taken requires a string tied to the type. I sure could create an instance everytime as a workaround and declare an abstract property, but that's not what I want. I want to enforce the declaration of the string at compile-time, just to be sure.
No, you can't. I would suggest you make your base class abstract, with an abstract property which you can fetch when you want. Each child class can then implement the property just by returning a constant if it wants. The downside is that you can't use this within static methods in the base class - but those aren't associated with the child classes anyway.
(It also allows child classes to customise the property per instance as well, if necessary... but that's rarely an actual problem.)
If this doesn't do enough for you, you might want to consider a parallel type hierarchy. Basically polymorphism simply doesn't happen in a type-specific way in .NET; only in an instance-specific way.
If you still want to do this and fetch it with reflection, I suggest you just write unit tests to ensure that the relevant constants are defined. When you get beyond what the type system can describe, that's often the best you can do.
Make an abstract property with only a get. That's what I think you could do to enforce a class has a value. Then you can just return a constant in the property.
Example:
Base class:
public abstract string MyConst { get; }
Derived class:
public override string MyConst {
get { return "constant"; }
}
Here is how I made mine work. I used Attribute as others have suggested.
public class ObjectAttribute : Attribute
{
public int ObjectSize { get; set; }
public ObjectAttribute(int objectSize)
{
this.ObjectSize = objectSize;
}
}
public abstract class BaseObject
{
public static int GetObjectSize<T>() where T : IPacket
{
ObjectAttribute[] attributes = (ObjectAttribute[])typeof(T).GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
}
[ObjectAttribute(15)]
public class AObject : BaseObject
{
public string Code { get; set; }
public int Height { get; set; }
}
[ObjectAttribute(25)]
public class BObject : BaseObject
{
public string Code { get; set; }
public int Weight { get; set; }
}
If you would like instance access to the attribute just add it to the base abstract class.
public abstract class BaseObject
{
public static int GetObjectSize<T>() where T : IPacket
{
ObjectAttribute[] attributes = (ObjectAttribute[])typeof(T).GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
public int ObjectSize
{
get
{
ObjectAttribute[] attributes = (ObjectAttribute[])GetType().GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
}
}
Usage of the constants
int constantValueA = AObject.GetObjectSize<AObject>();
int constantValueB = BObject.GetObjectSize<BObject>();
AObject aInstance = new AObject();
int instanceValueA = aInstance.ObjectSize;
New idea
Here's a sort of weird idea: instead of using inheritance directly, you create a separate class to provide a constant value for every type deriving from some type T. The constructor for this type uses reflection to verify that every derived type has indeed been supplied a value.
public abstract class Constant<T, TConstant>
{
private Dictionary<Type, TConstant> _constants;
protected Constant()
{
_constants = new Dictionary<Type, TConstant>();
// Here any class deriving from Constant<T, TConstant>
// should put a value in the dictionary for every type
// deriving from T, using the DefineConstant method below.
DefineConstants();
EnsureConstantsDefinedForAllTypes();
}
protected abstract void DefineConstants();
protected void DefineConstant<U>(TConstant constant) where U : T
{
_constants[typeof(U)] = constant;
}
private void EnsureConstantsDefinedForAllTypes()
{
Type baseType = typeof(T);
// Here we discover all types deriving from T
// and verify that each has a key present in the
// dictionary.
var appDomain = AppDomain.CurrentDomain;
var assemblies = appDomain.GetAssemblies();
var types = assemblies
.SelectMany(a => a.GetTypes())
.Where(t => baseType.IsAssignableFrom(t));
foreach (Type t in types)
{
if (!_constants.ContainsKey(t))
{
throw new Exception(
string.Format("No constant defined for type '{0}'.", t)
);
}
}
}
public TConstant GetValue<U>() where U : T
{
return _constants[typeof(U)];
}
}
Basic example:
public class BaseType
{
public static Constant<BaseType, string> Description { get; private set; }
static BaseType()
{
Description = new BaseTypeDescription();
}
}
public class DerivedType : BaseType
{ }
internal sealed class BaseTypeDescription : Constant<BaseType, string>
{
public BaseTypeDescription() : base()
{ }
protected override DefineConstants()
{
DefineConstant<BaseType>("A base type");
DefineConstant<DerivedType>("A derived type");
}
}
Now I have code that allows me to do this:
var description = BaseType.Description;
// returns "A base type"
string baseTypeDescription = description.GetValue<BaseType>();
// returns "A derived type"
string derivedTypeDescription = description.GetValue<DerivedType>();
Original answer
You may not like it, but the closest way to accomplish this is by declaring an abstract read-only (no set) property.
If you've got an instance of your subclass, then this can work just as well as a constant, even though it is technically instance-level (it will just be the same for all instances of the given class).
Consider, for instance, IList.IsReadOnly. In most cases this is actually a property that tells you about the underlying class implementation, as opposed to any state specific to a particular instance. (It may be an interface member as opposed to an abstract class member, but it's the same idea.)
If you are trying to access it statically, well... then you're out of luck. But in this case I fail to see how you'd obtain the value without using reflection anyway. Maybe that's your intention; I don't know.
You could have a static method in the base class called, for instance "Register", that is passed a Type and a constant value, with the intention being that it is called by the class constructors of the subtypes. Then, add a check in all of your base class constructors that the object being constructed is of a registered type.
abstract class Base
{
private static Dictionary<Type, string> _registry = new Dictionary<Type, string>();
protected static void Register(Type t, string constVal)
{
_registry.Add(t, constVal);
}
protected Base()
{
if(!_registry.ContainsKey(this.GetType()))
throw new NotSupportedException("Type must have a registered constant");
}
public string TypeConstant
{
get
{
return _registry[this.GetType()];
}
}
}
class GoodSubtype : Base
{
static GoodSubtype()
{
Base.Register(typeof(GoodSubtype), "Good");
}
public GoodSubtype()
: base()
{
}
}
class Badsubtype : Base
{
public Badsubtype()
: base()
{
}
}
And then elsewhere, you can construct GoodSubtype instances, but trying to construct a Badsubtype gets an exception. I think a runtime error at construction is the soonest you can get an error with this type of scheme.
(You'd want to use ConcurrentDictionary for your registry if threading is involved)
There's one other method that hasn't been covered and it uses the new modifier to hide consts values in the base class. In a way, it's similar to Nap's solution, but doesn't allow per-instance access and therefore doesn't allow for polymorphic access within the base class. This solution is only useful if you want to have constant value defined but wish to have the option of changing it to different values in different subclasses.
static void Main(string[] args)
{
Console.WriteLine("BaseClass.MyConst = {0}, ClassA.MyConst = {1}, ClassB.MyConst = {2}", BaseClass.MyConst, ClassA.MyConst, ClassB.MyConst);
Console.ReadKey();
}
class BaseClass
{
public const int MyConst = 1;
}
class ClassA : BaseClass
{
public new const int MyConst = 2;
}
class ClassB : BaseClass
{
}