Implement interface and use code from existing implementation of the interface - c#

I'm trying to implement the ITableEntity interface so that I can add [DataContract] attribute on it. But if I implement this interface myself, I'll have to give the ReadEntity and WriteEntity methods a body.
But there is a class that already implements the ITableEntity interface and gave ReadEntity and WriteEntity methods a body, which is the TableEntity.cs.
How can I make my implementation of the interface use the methods in the TableEntity class?
[Edit]
[DataContract]
public class SerializableTableEntity : ITableEntity
{
private TableEntity tableEntity;
public string ETag { get; set; }
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTimeOffset Timestamp { get; set; }
public SerializableTableEntity()
{
tableEntity = new TableEntity();
}
public void ReadEntity(IDictionary<string, EntityProperty> properties, Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
tableEntity.ReadEntity(properties, operationContext);
}
public IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
return tableEntity.WriteEntity(operationContext);
}
}

The reason that every property in your stored table is blank is because WriteEntity and ReadEntity use the blank object to store and write the data.
You're delegating serialization of your object to 'tableEntity' but none of your properties are there.
Suggestion: you will need to implement all of your SerializableTableEntity's properties inside a class that derives from TableEntity, contain a variable of that type inside the SerializableTableEntity entity, and delegate every member's property get/set from SerializableTableEntity to this new object.
Does this make sense?
EDIT: Code sample as requested (you're not going to enjoy it though)
[DataContract]
public class SerializableTableEntity : ITableEntity
{
private CustomEntity tableEntity;
public string ETag {
{
get
{
return tableEntity.ETag;
}
set
{
tableEntity.Etag = value;
}
}
public string PartitionKey
{
get
{
return tableEntity.PartitionKey;
}
set
{
tableEntity.PartitionKey = value;
}
}
public string RowKey
{
get
{
return tableEntity.RowKey;
}
set
{
tableEntity.RowKey = value;
}
}
public DateTimeOffset Timestamp
{
get
{
return tableEntity.Timestamp;
}
set
{
tableEntity.Timestamp = value;
}
}
public string PropertyOne
{
get
{
return tableEntity.PropertyOne;
}
set
{
tableEntity.PropertyOne = value;
}
}
public SerializableTableEntity()
{
tableEntity = new CustomEntity();
}
public void ReadEntity(IDictionary<string, EntityProperty> properties, Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
tableEntity.ReadEntity(properties, operationContext);
}
public IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
return tableEntity.WriteEntity(operationContext);
}
}
public class CustomEntity : TableEntity
{
public string PropertyOne { get; set; }
}

I ended up creating exact copy of these classes and made them Serializable. But being able to do some complex queries seems to be a challenge as well. So we moved to SQL Database.

Either delegate the "uninteresting" methods (a more realistic example is here):
class YourClass : Interface {
public void ReadEntity()
{
delegateTo.ReadEntity();
}
TableEntity delegateTo = new TableEntity();
}
or just throw an exception inside them (like NotImplementedException) - the latter will only work for you if those methods are not called.

You can create a class that contains the implementation of the TableEntity class, but also adds the functionality that you want. This is similar to the Decorator Pattern.
[Attributes...]
public class MyTableEntity : ITableEntity {
private TableEntity decoratedTableEntity;
public void ReadEntity(args...) {
decoratedTableEntity.ReadEntity(args...);
}
}
To make the solution more generic, change decoratedTableEntity to be an ITableEntity.

Related

C# satisfy members of two interfaces with one property

Issue origin: I have a generic component to display data. The data may come from different data models. To unify the access inside the component I created one interface IOne that gets implemented by all classes. In order to abstract the data access layer from the application I'm using interfaces for each data model. So each data display model implements the IOne interface and additionally one of the data model interfaces.
The interfaces:
public interface IOne
{
public int idNameOne { get; set; }
}
public interface DataModelOne
{
public int anotherNameForId{ get; set; }
}
In my class I want both members to be satisfied by one single property. My current solution is as follows:
public class Implementation : IOne, DataModelOne
{
private int _id;
public idNameOne { get { return _id; } set { _id = value; } }
public anotherIdName { get { return _id; } set { _id = value; } }
}
Is there any way to declare that one property satisfies both members? What would be a clean solution for this?
No, there's no other way than what you are doing. I'd however clean up the code (and do proper casing), by removing the backing field (and use one auto-property) and only have the other one reference the first... something like:
public class Implementation : IOne, IDataModelOne
{
public int IdNameOne { get; set }
public int AnotherIdName { get => IdNameOne; set => IdNameOne = value; }
}
(notice I've used the proper casing for the properties... should be the same casing on the interfaces too... also named IDataModelOne correctly, with an I prefix)
To avoid having both on the public API, you should usually use "explicit interface implementation" for this, for example:
public class Implementation : IOne, DataModelOne
{
public int idNameOne { get; set; }
int DataModelOne.anotherNameForId
{
get => idNameOne;
set => idNameOne = value;
}
}
or
public class Implementation : IOne, DataModelOne
{
public int Id { get; set; }
int IOne.idNameOne
{
get => Id;
set => Id = value;
}
int DataModelOne.anotherNameForId
{
get => Id;
set => Id = value;
}
}
If I really had to do this I would make the idNameOne property an auto property with anotherIdName's getter and setter referring to that property.
public class Implementation : IOne, DataModelOne
{
public idNameOne { get; set; }
public anotherIdName { get { return idNameOne; } set { idNameOne = value; } }
}
It's a little bit cleaner and show the intention a little better too.

How to add deserialize method to abstract class

I have an idea, but I don't understand how to do it.
I've created an abstract class AJsonSerializer. And there I want to Serialize and Deserialize classes.
public abstract class AJsonSerializer {
public string ToJson() {
return JsonConvert.SerializeObject(this);
}
public T FromJson<T>(string jsonString) where T : class {
return JsonConvert.DeserializeObject<T>(jsonString);
}
}
I have a class User where I inherited from my abstract class:
public class User : AJsonSerializer {
public string PublicKey { get; set; }
public int User_ID { get; set; }
}
And now I can do like that
internal static void Get_UserData(string username, ref User user) {
if (ReadFromCache(username, out string value)) {
user = user.FromJson<User>(value);
} else {
DataAccess.Get_UserData(username, out string user_public_key, out int id_user);
user.PublicKey = user_public_key;
user.User_ID = id_user;
value = user.ToJson();
SaveToCashe(username, value);
}
}
This row looks ugly: user = user.FromJson<User>(value);
I want to do it like that: user.FromJson(value);
I know how I can do it in class User (example below), but I want to do it in abstract class and then this method will work for all my classes
Bad method how to solve it, just add initializer to class User like there:
public User(string jsonString) {
User user = JsonConvert.DeserializeObject<ApiUser>(jsonString);
PublicKey = user.PublicKey;
User_ID = user.User_ID;
}
Similar to Jerries answer, another option is just an extension method. You can have a constraint for T to be a AJsonSerializer to have it limited only to the subtypes of it. You can't override the extension method, but in your code you don't have it as virtual in the first place.
public static class SerializerExtensions {
public static T FromJson<T>(this T obj, string json) where T:AJsonSerializer {
JsonConvert.PopulateObject(json, obj);
return obj;
}
}
This way you won't need to implement passing of generic type throughout the inheritance chain.
But you need to initialize the value to access, so it would be:
var user = new User();
user.FromJson(jsonSTring);
or
var user = SerializerExtensions.FromJson(new User(), jsonString);
It's your decision what fits your use case better.
You could declare the generic type in your class definition
public class User : AJsonSerializer<User>
{
public string PublicKey { get; set; }
public int User_ID { get; set; }
}
public abstract class AJsonSerializer<T>
where T : class
{
public string ToJson() {
return JsonConvert.SerializeObject(this);
}
public static T FromJson(string jsonString) {
return JsonConvert.DeserializeObject<T>(jsonString);
}
}
Edit: and as Kara stated in his comment, your FromJson method can be static. So you can call it like
var user = User.FromJson(jsonString);

Returning a generic object without knowing the type?

I'm still fairly new to programming and have been tasked with creating a WebHook consumer that takes in a raw JSON string, parses the JSON into an object, which will be passed into a handler for processing. The JSON is coming in like this:
{
"id":"1",
"created_at":"2017-09-19T20:41:23.093Z",
"type":"person.created",
"object":{
"id":"person1",
"created_at":"2017-09-19T20:41:23.076Z",
"updated_at":"2017-09-19T20:41:23.076Z",
"firstname":"First",
...
}
}
The inner object can be any object so I thought this would be a great opportunity to use generics and built my class as follows:
public class WebHookModel<T> where T : class, new()
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
[JsonProperty(PropertyName = "object")]
public T Object { get; set; }
[JsonIgnore]
public string WebHookAction
{
get
{
return string.IsNullOrEmpty(Type) ? string.Empty : Type.Split('.').Last();
}
}
}
Then created the following interface:
public interface IWebHookModelFactory<T> where T : class, new()
{
WebHookModel<T> GetWebHookModel(string type, string jsonPayload);
}
What I'm failing to understand is how am I supposed to implement the Factory class without knowing what the type is at compile time?
Playing around with the Model a bit, I changed it to an abstract class with an abstract T object so that it could be defined by a derived class.
public abstract class WebHookModel<T> where T : class, new()
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
[JsonProperty(PropertyName = "object")]
public abstract T Object { get; set; }
[JsonIgnore]
public string WebHookAction
{
get
{
return string.IsNullOrEmpty(Type) ? string.Empty : Type.Split('.').Last();
}
}
}
public PersonWebHookModel : WebHookModel<Person>
{
public override Person Object { get; set; }
}
But I still run into the same issue of trying to implement an interface in which I don't know the type at runtime. From what I've found online, this is an example of covariance, but I haven't found any articles that explain how to resolve this issue. Is it best to skip generics and create a massive
case statement?
public interface IWebHookFactory<TModel, TJsonObject>
where TJsonObject : class, new()
where TModel : WebHookModel<TJsonObject>
{
TModel GetWebHookModel(string type, string jsonPayload);
}
I'm a bit partial to using the abstract class approach because it lets me define individual handlers based on which model I'm passing into my Service.
public interface IWebHookService<TModel, TJsonObject>
where TJsonObject : class, new()
where TModel : WebHookModel<TJsonObject>
{
void CompleteAction(TModel webHookModel);
}
public abstract class BaseWebhookService<TModel, TJsonObject> : IWebHookService<TModel, TJsonObject>
where TJsonObject : class, new()
where TModel : WebHookModel<TJsonObject>
{
public void CompleteAction(TModel webHookModel)
{
var self = this.GetType();
var bitWise = System.Reflection.BindingFlags.IgnoreCase
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.NonPublic;
var methodToCall = self.GetMethod(jsonObject.WebHookAction, bitWise);
methodToCall.Invoke(this, new[] { jsonObject });
}
protected abstract void Created(TModel webHookObject);
protected abstract void Updated(TModel webHookObject);
protected abstract void Destroyed(TModel webHookObject);
}
public class PersonWebHookService : BaseWebHookService<PersonWebHookModel, Person>
{
protected override void Created(PersonWebHookModel webHookModel)
{
throw new NotImplementedException();
}
protected override void Updated(PersonWebHookModel webHookModel)
{
throw new NotImplementedException();
}
protected override void Destroyed(PersonWebHookModel webHookModel)
{
throw new NotImplementedException();
}
}
Key points for the solution:
1. There needs to be some virtual call in there somewhere.
2. Somehow you need to map from your type tag in your JSON payload to your actual C# class.
IE, "person.created"," --> 'Person'.
If you control the serialization format, JSON.Net can inject its own type tag and do this for you. Assuming you can't go that route ...
So you'll need something like a Dictionary to contain the mapping.
Assuming your definitions is like:
abstract class WebhookPayload // Note this base class is not generic!
{
// Common base properties here
public abstract void DoWork();
}
abstract class PersonPayload : WebhookPayload
{
public override void DoWork()
{
// your derived impl here
}
}
And then you can deserialize like:
static Dictionary<string, Type> _map = new Dictionary<string, Type>
{
{ "person.created", typeof(PersonPayload)}
}; // Add more entries here
public static WebhookPayload Deserialize(string json)
{
// 1. only parse once!
var jobj = JObject.Parse(json);
// 2. get the c# type
var strType = jobj["type"].ToString();
Type type;
if (!_map.TryGetValue(strType, out type))
{
// Error! Unrecognized type
}
// 3. Now deserialize
var obj = (WebhookPayload) jobj.ToObject(type);
return obj;
}

EmitMapper - Generic mapping from abstract model object to abstract DTO

I need some help transitioning from ValueInjecter to EmitMapper (I've decided so for performance reasons). My use case is one of the most common ones: mapping a Model object to a DTO, based on some rules.
One of this rules is: if a property's type is a subclass of DomainObject, then it should be mapped it to its correspondent DTO. With concrete types that's ok, but I also want it to work with abstract types. The problem is that I don't how to tell EmitMapper which DTO should be used, in a dynamic fashion.
In ValueInjecter code:
public bool IsDomainObjectAndTargetIsDto(ConventionInfo it)
{
return it.SourceProp.Value.IsNotNull()
&& typeof(DomainObject).IsAssignableFrom(it.SourceProp.Type)
&& it.TargetProp.Type.Name.EndsWith("DTO");
}
As all of my DTOs implements DTO<> interface, I thought I could use EmitMapper's DefaultMapConfig.ConvertGeneric method but I just can't figure out how.
Just for completeness, I include my current (not working) code:
public class ModelToDtoConventions()
{
public IMappingConfigurator GetConfig()
{
return new DefaultMapConfig()
.ConvertUsing<IdentificableObject, int>(o => o.Id)
.ConvertGeneric(
typeof (DomainObject),
typeof (DTO<>),
new DefaultCustomConverterProvider(
typeof (DomainObjectToDtoConverter<>)
)
);
}
}
public class DomainObjectToDtoConverter<TDomainObject>
{
public DTO<TDomainObject> Convert(TDomainObject from, object state)
{
return (DTO<TDomainObject>)this.CreateDtoFor(#from);
}
private object CreateDtoFor(object modelObject)
{
var modelType = modelObject.GetType();
var dtoInterface = typeof(DTO<>).MakeGenericType(modelType);
var dtoType = dtoInterface
.GetConcreteSubtypes()
.Single();
return Activator.CreateInstance(dtoType);
}
}
When I try to use this mapping on a test, I'm getting the following exception
'MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model' failed: System.ArgumentException : Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
at EmitMapper.MappingConfiguration.MapConfigBaseImpl.GetGenericConverter(Type from, Type to)
at EmitMapper.MappingConfiguration.MapConfigBaseImpl.FilterOperations(Type from, Type to, IEnumerable`1 operations)
at EmitMapper.MappingConfiguration.DefaultMapConfig.GetMappingOperations(Type from, Type to)
at EmitMapper.EmitBuilders.MappingBuilder.BuildCopyImplMethod()
at EmitMapper.ObjectMapperManager.BuildObjectsMapper(String MapperTypeName, Type from, Type to, IMappingConfigurator mappingConfigurator)
at EmitMapper.ObjectMapperManager.GetMapperInt(Type from, Type to, IMappingConfigurator mappingConfigurator)
at EmitMapper.ObjectMapperManager.GetMapperImpl(Type from, Type to, IMappingConfigurator mappingConfigurator)
at MyProject.WebApi.Adapters.DTOInjector.Transform[TDestination](IMappingConfigurator config, Object source, TDestination destination) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 56
at MyProject.WebApi.Adapters.DTOInjector.CreateDto[TDTO](Object entity) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 47
at MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model() in c:\Users\faloi\Documents\GitHub\api\WebApi.Test\Utils\DTOInjectorTest.cs:line 334 c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs 56
EDIT: this is an example of objects that I'd like to map.
//Domain objects
public class Game
{
public IEnumerable<Map> Maps { get; set; }
public Map MostPlayedMap { get; set; }
public Game()
{
this.Maps = new List<Map>();
}
}
public abstract class Map : DomainObject
{
public string Name { get; set; }
}
public class BombDefuseMap : Map
{
public Player BombHolder { get; set; }
}
public class HostageRescueMap : Map
{
public int QuantityOfHostages { get; set; }
}
//DTOs
public class GameDTO : DTOWithId<Game>
{
public List<MapDTO> Maps { get; set; }
public MapDTO MostPlayedMap { get; set; }
}
public abstract class MapDTO
{
public string Name { get; set; }
}
public class BombDefuseMapDTO : MapDTO, DTO<BombDefuseMap>
{
public int BombHolder { get; set; }
}
public class HostageRescueMapDTO : MapDTO, DTO<HostageRescueMap>
{
public int QuantityOfHostages { get; set; }
}
if you're concerned about performance have a look at this page:
http://valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection
it's an injections that performs much better but you don't get the value in the matching algorithm,
most times you don't need it anyway

Register abstract managed classes with generic managing class and preserve one-to-many relationship

I have a couple abstract classes, and would like to make sure that the "Manager" is always registered with the "Managed" class such that they retain a two-way knowledge of the one-to-many relationship. That is, the Manager knows all of the Managed classes it has, and the Managed class knows who its Manager is (if it is registered with one). Further, I'd like the managed class to be able to call the specialization of its concrete manager without having to do a special cast. Is that possible?
I'd like something like this, but run into compilation issues:
class Program
{
static void Main(string[] args)
{
ConcreteManager manager = new ConcreteManager();
ConcreteManaged managed = new ConcreteManaged() { Name = "Test" };
manager.Add(managed);
managed.Process();
}
}
public abstract class BaseManager<ManagedType>
where ManagedType : BaseManaged
{
protected Dictionary<string, ManagedType> registered = new Dictionary<string, ManagedType>();
public void Add(ManagedType managed)
{
managed.Manager = this; // Cannot implicitly convert type 'BaseManager<ManagedType>' to 'BaseManager<BaseManaged>' (I've tried casting to no avail)
registered.Add(managed.Name, managed);
}
// Other common management tasks
}
public class ConcreteManager : BaseManager<BaseManaged>
{
//specialization stuff, e.g.
public void Refresh() { Console.WriteLine("Refresh Called"); }
}
public abstract class BaseManaged
{
public string Name { get; set; }
public BaseManager<BaseManaged> Manager { get; set; }
}
public class ConcreteManaged : BaseManaged
{
//specialization stuff, e.g.
public void Process()
{
Manager.Refresh();
}
}
If I change the non Program classes around a bit, as follows, I can get it to compile, but there are runtime errors (Unable to cast object of type 'TestAbstractGenerics.ConcreteManager' to type 'TestAbstractGenerics.IBaseManager`1[TestAbstractGenerics.IBaseManaged]'.):
public interface IBaseManager<ManagedType>
where ManagedType : IBaseManaged
{
void Add(ManagedType service);
}
public abstract class BaseManager<ManagedType> : IBaseManager<ManagedType>
where ManagedType : IBaseManaged
{
protected Dictionary<string, ManagedType> registered = new Dictionary<string, ManagedType>();
public void Add(ManagedType managed)
{
managed.Manager = (IBaseManager<IBaseManaged>)this;
registered.Add(managed.Name, managed);
}
// Other common management tasks
}
public class ConcreteManager : BaseManager<BaseManaged>
{
//specialization stuff, e.g.
public void Refresh() { Console.WriteLine("Refresh() called"); }
}
public interface IBaseManaged
{
string Name { get; set; }
IBaseManager<IBaseManaged> Manager { get; set; }
}
public abstract class BaseManaged : IBaseManaged
{
public string Name { get; set; }
public IBaseManager<IBaseManaged> Manager { get; set; }
}
public class ConcreteManaged : BaseManaged
{
//specialization stuff, e.g.
public void Process()
{
((ConcreteManager)Manager).Refresh();
}
}
If I change the IBaseManager<IBaseManaged> to dynamic I can remove the cast from Process() and everything works as expected, but dynamic doesn't work with intellisense, and I would like to be able to enforce the type checking (so an implementer can't accidentally set Manager to a string, for example). So what's the best practice here? Is there a good pattern to follow that allows me to preserve the one-to-many relationship?
And yes, in the above I'd have to add some logic to make sure that when BaseManaged.Manager is set that it unregisters from its current Manager, if any. I avoided that here for sake of simplicity.
Edit: this works, but still requires casting to the ConcreteManager prior to calling its non-interface methods:
class Program
{
static void Main(string[] args)
{
var manager = new ConcreteManager();
var managed = new ConcreteManaged() { Name = "Test"};
manager.Add(managed);
managed.Process();
}
}
public interface IBaseManager<ManagedType>
where ManagedType : IBaseManaged
{
void Add(ManagedType managed);
}
public abstract class BaseManager<ManagedType> : IBaseManager<ManagedType>
where ManagedType : IBaseManaged
{
protected Dictionary<string, ManagedType> registered = new Dictionary<string, ManagedType>();
public void Add(ManagedType managed)
{
managed.Manager = (IBaseManager<IBaseManaged>)this;
registered.Add(managed.Name, managed);
}
// Other common management tasks
}
public class ConcreteManager : BaseManager<IBaseManaged>
{
//specialization stuff, e.g.
public void Refresh() { Console.WriteLine("Refresh() called"); }
}
public interface IBaseManaged
{
string Name { get; set; }
IBaseManager<IBaseManaged> Manager { get; set; }
}
public abstract class BaseManaged : IBaseManaged
{
public string Name { get; set; }
public IBaseManager<IBaseManaged> Manager { get; set; }
}
public class ConcreteManaged : BaseManaged
{
//specialization stuff, e.g.
public void Process()
{
((ConcreteManager)Manager).Refresh();
}
}
I'm pretty sure the kind of cyclic relationship you want is not possible to implement perfectly type safe and without casts, because the compiler would end up getting into infinite cycles if you wanted IBaseManaged also to be generic (ie, IBaseManaged<T> where T : IBaseManager<?>), is clearly not possible to specify the constraint you need in place of ?.
You can however, create a third interface/class which can fully express this kind of circular constraint, which might provide an alternative solution.
interface IManagerAdapter<TManager, TManaged>
where TManager : IBaseManager<TManaged>
where TManaged : IBaseManaged<TManager>
IMO, if your ConcreteManaged class is going to know directly about ConcreteManager by virtue of the type cast anyway, these classes don't really provide much more than a pattern to follow for concrete types, the abstraction is kind of broken. If you need this tight coupling between the specific concrete manager and managed types anyway, I would probably make it explicity by adding the specific type in place of Managed in each class, and do away with the BaseManaged class, which doesn't help very much other than providing the Name, which is simple enough to re-implement in concrete instances.
public interface IBaseManaged<T> {
string Name { get; set; }
T Manager { get; set; }
}
public class ConcreteManaged : IBaseManaged<ConcreteManager> {
public string Name { get; set; }
public ConcreteManager Manager { get; set; }
public void Process ()
{
Manager.Refresh ();
}
}
For anything in the base types which might be more complex to implement than Name, I would opt for a Mixin like approach, where you implement that additional functionality in a separate class, and just provide a property in the interface to retreive the Mixin. For example, if all the Manager classes need to account for registering all of the Managed (as with your Add()), you obviously don't want to duplicate that functionality in each Manager - but you could simplify the approach by implementing some ManagedRegister<T> type, say (can be whatever you like), and giving the IBaseManager type a Registered field to retreive an instance.
public interface IBaseManager<T> {
ManagedRegister<T> Registered { get; set; }
}
public class ConcreteManager : IBaseManager<ConcreteManaged> {
public ManagedRegister<ConcreteManaged> Registered { get; set; }
public void Refresh () { Console.WriteLine("Refresh() called"); }
}
You still get a strongly typed Managed instances from the Register inside the Manager here.
The change from your calling code is that instead of manager.Add(managed), it becomes manager.Registered.Add(managed), and you also need to create an instance of ManagedRegister<ConcreteManaged> to pass to the ConcreteManager.. Perhaps a bit messy, and I would suggest abstracting that away into a factory, which will prevent simple mistakes like forgetting to add managed instances to the manager. We can use that circular constraint from above to implement it in a type safe way. (And if it's possible to assume every Managed/Manager has a parameterless constructor, a single implementation will work by using new() constraints. Otherwise you'll want an abstract factory and implement for each concrete type).
interface IManagerFactory<TManager, TManaged>
where TManager : IBaseManager<TManaged>
where TManaged : IBaseManaged<TManager>
{
TManager Manager { get; }
TManaged Create (string name);
}
public abstract class ManagerFactory<TManager, TManaged>
: IManagerFactory<TManager, TManaged>
where TManager : IBaseManager<TManaged>, new()
where TManaged : IBaseManaged<TManager>, new()
{
TManager manager = new TManager ();
public ManagerFactory () {
manager.Registered = new ManagedRegister<TManaged> ();
}
public TManager Manager { get { return manager; } }
public TManaged Create (string name)
{
TManaged result = new TManaged ();
result.Name = name;
manager.Registered.Add (result.Name, result);
result.Manager = manager;
return result;
}
}
public class ConcreteFactory
: ManagedFactory<ConcreteManager, ConcreteManaged> { }
Back to Main, the usage is slightly simplified here.
ConcreteFactory f = new ConcreteFactory ();
ConcreteManaged managed = f.CreateManaged ("Test");
managed.Process ();
EDIT:
Here's abstracting all of the common functionality into so called "Base classes". The key difference here is that the Base classes composed into the concrete class rather than inherited, by means of the Base property, which acts very much like the base. prefix you'd use to call base members usually.
public class BaseManager<T> {
public Dictionary<string, T> Registered { get; set; }
}
public interface IBaseManager<T> {
BaseManager<T> Base { get; set; }
}
public class ConcreteManager
: IBaseManager<ConcreteManaged> {
public BaseManager<ConcreteManaged> Base { get; set; }
public void Refresh() { Console.WriteLine("Refresh() called"); }
}
public class BaseManaged<T> {
public string Name { get; set; }
public T Manager { get; set; }
}
public interface IBaseManaged<T> {
BaseManaged<T> Base { get; set; }
}
public class ConcreteManaged
: IBaseManaged<ConcreteManager> {
public BaseManaged<ConcreteManager> Base { get; set; }
internal ConcreteManaged () { }
public void Process () {
Base.Manager.Refresh ();
}
}
interface IManagerFactory<TManager, TManaged>
where TManager : IBaseManager<TManaged>
where TManaged : IBaseManaged<TManager> {
TManager Manager { get; }
TManaged Create (string name);
}
public abstract class BaseManagerFactory<TManager, TManaged>
: IManagerFactory<TManager, TManaged>
where TManager : IBaseManager<TManaged>, new()
where TManaged : IBaseManaged<TManager>, new() {
TManager manager = new TManager();
public BaseManagerFactory() {
manager.Base = new BaseManager<TManaged>();
manager.Base.Registered = new Dictionary<string, TManaged>();
}
public TManager Manager { get { return manager; } }
public TManaged Create (string name) {
TManaged result = new TManaged();
result.Base = new BaseManaged<TManager>();
result.Base.Name = name;
manager.Base.Registered.Add (name, result);
result.Base.Manager = manager;
return result;
}
}

Categories