I'm making a form application with a 'propertygrid control.'
I want all properties to always display with non-bold text --- always treat all properties as a 'default' value. And this 'Test' class has a lot of properties.
I think the best way is to dynamically implement 'ShouldSerializeXXX' methods. Manually implementation is lacking in flexibility and not smart.
I know the way to dynamically implement a function using ’DynamicMethod class' [https://learn.microsoft.com/en-US/dotnet/api/system.reflection.emit.dynamicmethod?view=net-5.0]. But the 'ShouldSerializeXXX' function has an effect just by defining, I have no idea how to implement the function.
Can anybody tell me the way to do this? Sorry for my poor English.
public class Test
{
public int AAA {get;set;}
public string BBB {get;set;}
public bool CCC {get;set;}
...
...
//This class has a lot of property, so I want to dynamically implement the function like this:
private bool ShouldSerializeAAA(){ return false; }
private bool ShouldSerializeBBB(){ return false; }
...
}
Dynamically implementing a method that needs to then be discovered by reflection is not trivial, and would require dynamically creating a sub-type of Test and making sure that all your instances are actually of the sub-type - not an appealing proposition.
There are some more appealing options, though;
generate the extra methods - this could be a few lines of throw-away reflection code (and a unit test that checks that they all exist) that just spits out however-many versions of public bool ShouldSerialize{Name}() => false;
look into the type-descriptor/property-descriptor API; a custom type-description-provider can provide custom property-descriptors, and it is they that get to say whether something needs to be serialized or not; it is just that the default implementation looks for ShouldSerialize{Name}()
Honestly, option 1 seems by far the easiest option here - and it will involve less mess at runtime; you could get option 1 implemented in a few minutes, including the test to make sure you don't miss any new ones
The basic idea is using a custom type descriptor as it's already addressed in Marc's answer. You can see an implementation in my post here. You can make the linked post working for you easily by changing override of ShouldSerializeValue and return false. That's all.
But here I'd like to share another option, a shorter answer, which needs less effort but basically do the same for you. Using a Proxy when passing objects to PropertyGrid:
Assuming you have a common class like this:
public class MyClass
{
public string MyProperty1 { get; set; }
public string MyProperty2 { get; set; }
public string MyProperty3 { get; set; }
}
This is how you use the proxy:
var myOriginalObject = new MyClass();
this.propertyGrid1.SelectedObject = new ObjectProxy(myOriginalObject);
And here is the result after changing properties:
This is the ObjectProxy which is a class derived from CustomTypeDescriptor will do the magic for you. And here's the class:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
public class ObjectProxy : CustomTypeDescriptor
{
public object Original { get; private set; }
public List<string> BrowsableProperties { get; private set; }
public ObjectProxy(object o)
: base(TypeDescriptor.GetProvider(o).GetTypeDescriptor(o)) => Original = o;
public override PropertyDescriptorCollection GetProperties(Attribute[] a)
{
var props = base.GetProperties(a).Cast<PropertyDescriptor>()
.Select(p => new MyPropertyDescriptor(p));
return new PropertyDescriptorCollection(props.ToArray());
}
public override object GetPropertyOwner(PropertyDescriptor pd) => Original;
}
public class MyPropertyDescriptor : PropertyDescriptor
{
PropertyDescriptor o;
public MyPropertyDescriptor(PropertyDescriptor originalProperty)
: base(originalProperty) => o = originalProperty;
public override bool CanResetValue(object c) => o.CanResetValue(c);
public override object GetValue(object c) => o.GetValue(c);
public override void ResetValue(object c) => o.ResetValue(c);
public override void SetValue(object c, object v) => o.SetValue(c, v);
public override bool ShouldSerializeValue(object c) => false;
public override AttributeCollection Attributes => o.Attributes;
public override Type ComponentType => o.ComponentType;
public override bool IsReadOnly => o.IsReadOnly;
public override Type PropertyType => o.PropertyType;
}
Related
I have a third party DLL that returns objects like Customers, Orders, etc. I'll call them Your Entities. They do have a common IYourEntity interface so I can use that as a source constraint.
I want to create a generic conversion extension method to convert all these different third party entities to My Entities with some streamlined and more maintainable code.
....but I can't figure out how to make a generic extension method that will call the concrete extension method for the specific conversion of each class.
Putting some of the main aspects of my code below, but you can get a full fiddle to play with here.
Yes, I'm probably showing I'm a bit clueless on how to do this and maybe trying to combine different concepts. Any pointers much appreciated as I've been beating my head for a couple of days now and need a life line :)
public interface IYourEntity
{
int Id
{
get;
set;
}
}
public interface IConvertToMyEntity<TYourEntity, TMyEntity>
where TYourEntity : class, IYourEntity, new()
where TMyEntity : class, IMyEntity, new()
{
TMyEntity ToMyEntity(TYourEntity yourEntity);
}
public static class ExtensionMethods
{
private static IMyEntity ToMyEntity(this IYourEntity yourEntity)
{
return new MyEntity1();
}
public static List<IMyEntity> ToMyEntityList(this List<IYourEntity> lstYourEntities)
{
return lstYourEntities.ConvertAll(q => q.ToMyEntity());
}
}
public class YourEntity1 : IYourEntity, IConvertToMyEntity<YourEntity1, MyEntity1>
{
public int Id
{
get;
set;
}
public string YourEntityName
{
get;
set;
}
public MyEntity1 ToMyEntity(YourEntity1 yourEntity)
{
return new MyEntity1()
{Id = yourEntity.Id, MyEntityName = yourEntity.YourEntityName, CreatedOn = DateTime.UtcNow};
}
public List<MyEntity1> ToMyEntityList(List<YourEntity1> lstYourEntities)
{
return lstYourEntities.ConvertAll(q => ToMyEntity(q));
}
}
Since the classes implementing IYourEntity are from a third party and not under your control, you can't implement an own IConvertToMyEntity<T1, T2> interface upon these.
One way you can handle it is by overloads of such conversion (extension) methods.
There's no need for any generic T type arguments; the common IYourEntity interface suffices.
Suppose you have 3 classes implementing the IYourEntity interface;
e.g. YourCustomer, YourOrder and YourProduct.
These need to be converted to IMyEntity instances, of which you might have different concrete implementations;
e.g. a general MyEntity and a specific MyProduct.
For the conversion you set up an extension method targeting IYourEntity.
This extension method will be called to convert an IYourEntity to an IMyEntity in case a more specific overload of this extension method does not exist.
public static IMyEntity ToMyEntity(this IYourEntity target)
{
return new MyEntity { Id = target.Id, EntityName = "Fallback name" };
}
For the entities that require a custom conversion, you set up overloads of this extension method targeting those specific source class types.
Below are such ones for YourOrder and YourProduct (but not for YourCustomer).
public static IMyEntity ToMyEntity(this YourOrder target)
{
return new MyEntity { Id = target.Id, EntityName = target.OrderName.ToUpper() };
}
public static IMyEntity ToMyEntity(this YourProduct target)
{
return new MyProduct { Id = target.Id * 100, EntityName = target.ProductName };
}
Next, define the extension method to convert the list of IYourEntity instances to a list of IMyEntity instances. In the code below, the inbetween cast to dynamic enables that the appropriate ToMyEntity overload will be called.
Note that the ToMyEntity methods don't have to be extension methods, but it might be convenient to have these in place in case you need to convert a single instance instead of a list.
public static List<IMyEntity> ToMyEntities(this List<IYourEntity> target)
{
var myEntities = new List<IMyEntity>();
foreach (var yourEntity in target)
{
var myEntity = Extensions.ToMyEntity((dynamic)yourEntity);
myEntities.Add(myEntity);
}
return myEntities;
}
An example - .net fiddle
var yourEntities = new List<IYourEntity>()
{
new YourCustomer() { Id = 1 },
new YourOrder() { Id = 2, OrderName = "Order-2"},
new YourProduct() { Id = 3, ProductName = "Product-3"}
};
var myEnties = yourEntities.ToMyEntities();
myEnties.ForEach(o => Console.WriteLine("{0} - {1} ({2})",
o.Id, o.EntityName, o.GetType().Name
));
The output of the example above looks like below.
Notice how the YourCustomer instance was handled by the general IYourEntity conversion, whereas the YourOrder and YourProduct instances got a specific treatment.
1 - Fallback name (MyEntity)
2 - ORDER-2 (MyEntity)
300 - Product-3 (MyProduct)
You can change your extension method to this:
private static IMyEntity ToMyEntity(this IYourEntity yourEntity)
{
if (yourEntity is IConvertToMyEntity<IYourEntity, IMyEntity> convertible)
return convertible.ToMyEntity;
return new MyEntity1();
}
This will not work in most cases unless you also make your interface co- and contra-variant:
public interface IConvertToMyEntity<in TYourEntity, out TMyEntity>
where TYourEntity : class, IYourEntity, new()
where TMyEntity : class, IMyEntity, new()
{
TMyEntity ToMyEntity(TYourEntity yourEntity);
}
It is still not completely clear to me how you can make a third party class implements IConvertToMyEntity that easily. Assuming you did this only to show us your actual goal, you should be very careful with what you are trying to accomplish in the Main.
If you use a List<IYourEntity>, you can only use methods and properties defined in the interface, unless you know what you are doing with specific cast. The need for List<IYourEntity> or List<IMyEntity> limits a lot the implementation of a custom mapper between My classes and Your classes. Here a possible solution:
As I said, I did not change Your classes:
public interface IYourEntity
{
int Id
{
get;
set;
}
}
public class YourEntity1 : IYourEntity
{
public int Id
{
get;
set;
}
public string YourEntityName
{
get;
set;
}
}
Also My classes are very simple and do not contain any logic for the mapping. This is a debatable choice, but I generally prefer to keep conversion logic separated from the classes involved. This helps to maintain clean your code in case you have several conversion functions for the same pair of classes. By the way, here they are:
public interface IMyEntity
{
int Id
{
get;
set;
}
DateTime CreatedOn
{
get;
set;
}
}
public class MyEntity1 : IMyEntity
{
public int Id
{
get;
set;
}
public string MyEntityName
{
get;
set;
}
public DateTime CreatedOn
{
get;
set;
}
}
And this is how I designed the custom converter
public interface IMyEntityConverter
{
IMyEntity Convert(IYourEntity yourEntity);
}
public class MyEntity1Converter : IMyEntityConverter
{
public IMyEntity Convert(IYourEntity yourEntity)
{
var castedYourEntity = yourEntity as YourEntity1;
return new MyEntity1()
{
Id = castedYourEntity.Id,
MyEntityName = castedYourEntity.YourEntityName,
CreatedOn = DateTime.UtcNow
};
}
}
It is clear the lack of genericity, but you cannot do otherwise if you need an extension method on a List of generic My and Your classes. Also tried with covariant and contravariant interfaces but C# does not let you use them with this implementation.
Now the core of the solution: you need something that binds Your class to the My class with a custom converter, and all of this should be as more transparent as possible.
public class EntityAdapter<YourType, MyType>
where YourType : IYourEntity
where MyType : IMyEntity
{
protected YourType wrappedEntity;
protected IMyEntityConverter converter;
public EntityAdapter(YourType wrappedEntity, IMyEntityConverter converter)
{
this.wrappedEntity = wrappedEntity;
this.converter = converter;
}
public static implicit operator YourType(EntityAdapter<YourType, MyType> entityAdapter) => entityAdapter.wrappedEntity;
public static explicit operator MyType(EntityAdapter<YourType, MyType> entityAdapter) =>
(MyType) entityAdapter.converter.Convert(entityAdapter.wrappedEntity);
public MyType CastToMyEntityType()
{
return (MyType) this;
}
}
The pseudo-transparency here is given by the implicit cast to Your class. The advantage is that you can cast this EntityAdapter to an instance of a My class by calling CastToMyEntityType or the explicit operator overload.
The painful part is with the extension methods:
public static class EntityAdapterExtensions
{
public static List<IMyEntity> ToIMyEntityList(this List<EntityAdapter<IYourEntity, IMyEntity>> lstEntityAdapters)
{
return lstEntityAdapters.ConvertAll(e => e.CastToMyEntityType());
}
public static List<EntityAdapter<IYourEntity, IMyEntity>> ToEntityAdapterList(this List<IYourEntity> lstYourEntities)
{
return lstYourEntities.Select(e =>
{
switch (e)
{
case YourEntity1 yourEntity1:
return new EntityAdapter<IYourEntity, IMyEntity>(yourEntity1, new MyEntity1Converter());
default:
throw new NotSupportedException("You forgot to map " + e.GetType());
}
}).ToList();
}
}
The first one is pretty straightforward to understand, but the second one is definitely something that require maintenance. I gave up on generics for the reasons already explained, so the only thing left to do is to create the EntityAdapters starting from the actual entity types.
Here is the fiddle
This may be a little controversial but maybe a different way is better?
Firstly, and this is more for my sake, I would suggest more easily understandable terminology so instead of 'your' and 'my' I would use 'source' and 'dest'.
Secondly I wonder if the generics route is necessary? I'm assuming (and I may be wrong) that for each of the classes you have coming from your third-party assembly, you have a specific class for it to be converted to. So maybe this could be achieved much more easily with a constructor override in your destination class.
// third party class example
public class SourceClass
{
public int Id { get; set; }
public string Name { get; set; }
}
// the destination class in your project
public class DestClass
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedOn { get; set; }
// default constructor
public DestClass()
{
}
// conversion constructor
public DestClass(SourceClass source)
{
Id = source.Id;
Name = source.Name;
CreatedOn = DateTime.UtcNow;
}
}
This way you convert a single instance using:
// source being an instance of the third-party class
DestClass myInstance = new DestClass(source);
And you can convert a list with LINQ:
// source list is IList<SourceClass>
IList<DestClass> myList = sourceList.Select(s => new DestClass(s)).ToList();
If you wanted to you could implement extensions for your conversions. This again would not be generic as you'll need one for each class pairing but as it's an alternative to writing a converter class for each, it will be overall less code.
public static class SourceClassExtensions
{
public static DestClass ToDest(this SourceClass source)
=> new DestClass(source);
public static IList<DestClass> ToDest(this IList<SourceClass> source)
=> source.Select(s => new DestClass(s)).ToList();
}
If you still want something generic then you'll want a converter for each class pair, implementing a suitable interface. Then I'd recommend a converter factory class where you'll need to register the specific converters either into a dictionary in the class or via dependency injection. I can go into this further if you'd prefer but I think it would be more complicated.
sorry for writing here its not an actual answer,
there is no option for generically to do this
you have to write for every entity
public interface IConvertToMyEntity<TYourEntity, TMyEntity>
where TYourEntity : class, IYourEntity, new()
where TMyEntity : class, IMyEntity, new()
{
TMyEntity ToMyEntity(TYourEntity yourEntity);
}
I saw this code from your question.
It depends on what you want to do after transformation
you should use data mapper
public class MapProfile : Profile
{
public MapProfile()
{
CreateMap<TYourEntity , TMyEntity >();
CreateMap<TMyEntity , TYourEntity >();
}
}
In my class ClassA : ISomeInterface i have:
public class ClassA : ISomeInterface {
Entity entity;
public void Test(){
if(entity.Target == this){}
}
}
With Target in entity defined as:
public class Entity {
public ISomeInterface Target {get; private set;}
}
My editor then gives me a warning:
Possible unintended reference comparison; to get a value comparison cast the LHS to type `Object`
Although it compiles, this is the first time I've had this warning. Should I not be comparing interface references like this?
As you already stated it is a warning not an error. And the warning tells you what the compiler really does and maybe your intentionnally guess what should happen is wrong.
So being said that, lets further dig what the problem could be. Here is some sample code (that what's being meant with please give an complete example):
using System;
public interface ISomeInterface
{
}
public class ClassA : ISomeInterface
{
public ClassA(int id)
{
Id = id;
}
public int Id { get; }
public ISomeInterface Entity { get; set; }
public static bool operator== (ClassA x, ClassA y)
{
return true;
}
public static bool operator!= (ClassA x, ClassA y)
{
return false;
}
public override bool Equals(object obj)
{
return true;
}
public override int GetHashCode()
{
return 72;
}
public void Test()
{
if (Entity == this)
{
Console.WriteLine("same");
}
else
{
Console.WriteLine("different");
}
}
}
public class Program
{
public static void Main()
{
var first = new ClassA(1);
var second = new ClassA(1);
first.Entity = second;
first.Test(); // writes "different"
}
}
As you can see the code implements the equality comparers and Equals(). All these methods are saying that all instance are the same, but the call in if(Entity == this) still tells that they are different.
This is the meaning of the warning and the root cause is, that an equality check of an interface always falls back to the implementation within the type object. And that implementation is ReferenceEquals(x, y).
So to avoid this warning and make your intention clear you should either explicitly write if(ReferenceEquals(Entity, this)) or implement a stand-alone class that implements IEqualityComparer<ISomeInterface> and use an instance of it if(new MyComparer().Equals(Enity, this)) (do not instantiate the comparer within the if statement in real code) to make your intentation of comparison obvious.
I currently have a class which encapsulates a list of typed objects and implements some interfaces like IEnumerable. I need a second class with additional, slightly different properties. So I will be creating a base class A and derive new class B and new class C from A.
However I have code (e.g like code for .Find using Delegates) which is almost the same in B and C. The only difference is that the code in B searches the private list of typed objects (let's say Person) and the code in C searches a private list of different objects (let's say Animal):
private static bool Find(Person xx)
{
if (xx.Id == someID)
{
return true;
}
else
{
return false;
}
}
As I want to avoid copying/pasting, my question is: What is a good strategy to avoid something like that?
The only way I imagined was to declare a list of generic objects in A and point the methods in A to that. In B and C I would then not have any code, however I lose all benefits of a typed list.
1) I would see if I could use generics when coding class A
public class cA<T>
{
private IEnumerable<T> _myPrivateData
public bool Find(args)
{
// Do stuff with _myPrivateData
}
}
public class cB : cA<TheTypeIWant>
{
// more stuff here if needed
}
2) You can use the property override feature + the use of the protected access modifier to do the following:
public class cA
{
protected IEnumerable<Object> MyData { get; set; }
public bool Find(args)
{
// Do stuff with MyData
}
}
public class cB : cA
{
protected new IEnumerable<MyOtherDataType> MyData { get; set; }
}
Of course MyOtherDataType has to inherit from the base type used for this approach to be possible. I would really not recommend this approach though. Option 1 is much better and cleaner.
Here's a few references that may prove to be useful:
http://peisker.net/dotnet/covariance.htm
C#: Overriding return types
I'd be tempted to have an interface like ICanBeFoundById
public interface ICanBeFoundById
{
int Id {get;}
}
then Person and Animal can both inherit from that and you can do something like
public static class FindExtensions
{
public static bool Find(this IEnumerable<ICanBeFoundById> xs, int someID)
{
return xs.Any(x=>x.Id == someID)
}
}
Warning: I haven't even checked if this compiles :)
Of course you could have some
public abstract class BaseRepository<ICanBeFoundById>
{
private IEnumerable<ICanBeFoundById> _xs;
public static bool Find(int someID)
{
return xs.Any(x=>x.Id == someID)
}
}
if you don't want to have a static extension.
I tried to search for solutions, but my problem is I don't even know what terms to use. Generics, Delegates, LINQ, Reflection, and Abstract ideas could be part of the solution, but my "Google-fu" isn't turning up the right answer.
Question:
I have multiple classes (ClassA, ClassB, ClassC) that all have the same 2-3 properties DoThisA, DoThisB, DoThisC.
The way the code works is that I always want to do the same code to set DoThisA, DoThisB, and DoThisC when I process each of the classes.
For example, to simplify, the logic will always be:
{some computations to set string currentValueImProcessing to something}
if (xyz) [ClassA|B|C].DoThisA = currentValueImProcessing
else [ClassA|B|C].DoThisB = currentValueImProcessing
I don't want to write those same statements over and over, so how do I just send a reference to the class (A,B,C) to a method to do the logic?
If it was written correctly each of ClassA, ClassB, and ClassC would have implemented some generic class and I could use that, but I cannot. Each of the classes are independent but have the same named properties.
Any guidance on concepts/code?
Thanks!
Create an interface for your properties:
internal interface IDoThis
{
public string DoThisA { get; set; }
public string DoThisB { get; set; }
public string DoThisC { get; set; }
}
Then, make your classes implement it:
public class ClassA : IDoThis
{
public string DoThisA { get; set; }
public string DoThisB { get; set; }
public string DoThisC { get; set; }
}
public class ClassB : IDoThis
{
// Same properties
}
public class ClassC : IDoThis
{
// Same properties
}
This, way, you'll be able to create a static initializer method somewhere:
internal static class MyClassesExtensions
{
public static void InitTheStuff(this IDoThis obj)
{
// Do something here, for example:
if (String.IsNullOrEmpty(obj.DoThisA))
obj.DoThisA = "foo";
else
obj.DoThisB = obj.DoThisC;
}
}
And then you can just call this.InitTheStuff() anywhere from ClassA, ClassB and ClassC.
you can either use reflection or you can use dynamic (dynamic will use reflection for you)
dynamic obj = new ClassA();
obj.DoTHisA();
is how to do it with dynamic
I am assuming that you are talking about classes that you intend to instantiate. If DoThisA,B,C are static methods then you must use reflection
NOTE - if you can change the classes then add an interface as others have suggested, or even a common base class
The reflection one looks like this
var type = obj.GetType(); // obj is ClassX object
var method = type.GetMethod("DoTHisA");
method.Invoke(obj);
I have not checked this - so the syntax might be a bit off - but this is the basic mechanics of reflection method calling. YOu need to get fancier if there are multiple methods with the same name, if the methods takses params etc
There are at least four options open to you - maybe more.
Create an interface, which is implemented by all of your classes and that includes the common methods.
Create a base class from which all classes inherit. The common functionality can then be implemented in the base class. If the implementation differs depending on the clases, but you can define common signatures for the methods, make your base class an the common funtionality abstract. You then can implement the actual functionality in each of your classes.
Use a dynamic object as in #pm100's solution.
Use reflection to access the common functionality.
As a guidance methods 1. and 2. are to be preferred, as they allow your code to be checked on compile time. If, however, you do not have control over the classes that contain the common functionality - for example you do not have access to the source code or you are permitted to make changes to the code - you can use the other two methods.
If you'd ask me which of the two I would prefer, I guess that I would go for 3. over 4. But this is personal preference.
Prob you are talking about inheritance.
For your task you need a base abstract class with general properties:
public abstract class Base
{
public bool DoThisA { get; set; }
public bool DoThisB { get; set; }
}
and child classes:
public class A : Base { }
public class B : Base { }
public class C : Base { }
After that you can create a method which will accept object of type Base
public void Do(Base b, bool xyz, bool currentValueImProcessing)
{
if (xyz)
{
b.DoThisA = currentValueImProcessing;
}
else
{
b.DoThisB = currentValueImProcessing;
}
}
There are already many methods provided here, so just for the sake of completeness... Here's some runtime code generation:
public class ClassA
{
public string DoThisA { get; set; }
public int DoThisB { get; set; }
public bool DoThisC { get; set; }
public void Init()
{
// You can call this from anywhere, even from an unrelated class
MyClassInitializer<ClassA>.Init(this);
}
}
public static class MyClassInitializer<T>
{
// Create the getters/setters you need, and make sure they're static.
private static readonly Func<T, string> _getA = BuildGetter<string>("DoThisA");
private static readonly Action<T, string> _setA = BuildSetter<string>("DoThisA");
private static readonly Func<T, int> _getB = BuildGetter<int>("DoThisB");
private static readonly Action<T, int> _setB = BuildSetter<int>("DoThisB");
private static readonly Func<T, bool> _getC = BuildGetter<bool>("DoThisC");
private static readonly Action<T, bool> _setC = BuildSetter<bool>("DoThisC");
private static Func<T, TValue> BuildGetter<TValue>(string name)
{
var obj = Expression.Parameter(typeof(T));
return Expression.Lambda<Func<T, TValue>>(Expression.Property(obj, name), obj).Compile();
}
private static Action<T, TValue> BuildSetter<TValue>(string name)
{
var obj = Expression.Parameter(typeof(T));
var value = Expression.Parameter(typeof(TValue));
return Expression.Lambda<Action<T, TValue>>(Expression.Assign(Expression.Property(obj, name), value), obj, value).Compile();
}
public static void Init(T obj)
{
// Here's your custom initialization method
if (_getA(obj) == "Foo")
_setB(obj, 42);
else
_setC(obj, true);
}
}
Not necessarily the easiest one to grasp, but this should be much faster than using dynamic or reflection. That said, if you don't need the speed, stick with dynamic as it's easier.
I'm having some problems trying to figure out how to solve a problem without being able to have static method in an abstract class or interface. Consider the following code. I have many Wizards that inherit from AbsWizard. Each wizard has a method GetMagic(string spell) that only returns magic for certain magic words, yet all instances of a specific type of wizard respond to the same set of magic words.
public abstract class AbsWizard
{
public abstract Magic GetMagic(String magicword);
public abstract string[] GetAvalibleSpells();
}
public class WhiteWizard : AbsWizard
{
public override Magic GetMagic(string magicword)
{
//returns some magic based on the magic word
}
public override string[] GetAvalibleSpells()
{
string[] spells = {"booblah","zoombar"};
return spells;
}
}
public class BlackWizard : AbsWizard
{
public override Magic GetMagic(string magicword)
{
//returns some magic based on the magic word
}
public override string[] GetAvalibleSpells()
{
string[] spells = { "zoogle", "xclondon" };
return spells;
}
}
I want the user to be able to first choose the type of wizard, and then be presented with a list of the spells that type of wizard can cast. Then when they choose a spell the program will find all, if any, existing wizards of the selected type and have them cast the selected spell. All wizards of a specific type will always have the same available spells, and I need a way to determine the spells a specific type of wizard can cast with out actually having access to an instance of the selected type of wizard.
In addition I don't want to have to depend on a separate list of possible wizard types or spells. Instead I would rather just infer everything through GetAvalibleSpells() and reflection. For example I plan to cast magic as follows:
public static void CastMagic()
{
Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();
List<Type> wizardTypes = new List<Type>();
List<string> avalibleSpells = new List<string>();
Type selectedWizardType;
string selectedSpell;
foreach (Type t in types)
{
if (typeof(AbsWizard).IsAssignableFrom(t))
{
wizardTypes.Add(t);
}
}
//Allow user to pick a wizard type (assign a value to selectedWizardType)
//find the spells the selected type of wizard can cast (populate availibleSpells)
//Alow user to pick the spell (assign a value to selectedSpell)
//Find all instances, if any exsist, of wizards of type selectedWizardType and call GetMagic(selectedSpell);
}
I think this is very bad style. You write the code, so you should know what wizard-classes you have in there. It's very bad style (and slow!) to run through all types via reflection and check if they derive from AbsWizard.
The Managed Extensibility Framework (available through codeplex for pre-.NET-4.0, or built-in .NET 4.0 in the System.ComponentModel.Composition namespace) was built for this. Say you have a service that can ask a user to select a wizard and then create it. It uses a wizard provider to create the wizards, and needs to know the name and available spells (metadata) for the wizards that a provider creates. You might use interfaces like these:
namespace Wizardry
{
using System.Collections.Generic;
public interface IWizardProvider
{
IWizard CreateWizard();
}
public interface IWizard
{
IMagic GetMagic(string magicWord);
}
public interface IWizardProviderMetadata
{
string Name { get; }
IEnumerable<string> Spells { get; }
}
}
The wizard creation service imports the available wizard providers, selects one through some mechanism (user feedback in your case), and uses the provider to create the wizard.
namespace Wizardry
{
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
public class UserWizardCreationService
{
[Import]
private IEnumerable<Lazy<IWizardProvider, IWizardProviderMetadata>> WizardProviders { get; set; }
public IWizard CreateWizard()
{
IWizard wizard = null;
Lazy<IWizardProvider, IWizardProviderMetadata> lazyWizardProvider = null;
IWizardProvider wizardProvider = null;
// example 1: get a provider that can create a "White Wizard"
lazyWizardProvider = WizardProviders.FirstOrDefault(provider => provider.Metadata.Name == "White Wizard");
if (lazyWizardProvider != null)
wizardProvider = lazyWizardProvider.Value;
// example 2: get a provider that can create a wizard that can cast the "booblah" spell
lazyWizardProvider = WizardProviders.FirstOrDefault(provider => provider.Metadata.Spells.Contains("booblah"));
if (lazyWizardProvider != null)
wizardProvider = lazyWizardProvider.Value;
// finally, for whatever wizard provider we have, use it to create a wizard
if (wizardProvider != null)
wizard = wizardProvider.CreateWizard();
return wizard;
}
}
}
You can then create and export an arbitrary number of wizard providers with spells, and the creation service will be able to find them:
namespace Wizardry
{
using System.ComponentModel.Composition;
[Export(typeof(IWizardProvider))]
[Name("White Wizard")]
[Spells("booblah", "zoombar")]
public class WhiteWizardProvider : IWizardProvider
{
public IWizard CreateWizard()
{
return new WhiteWizard();
}
}
[Export(typeof(IWizardProvider))]
[Name("White Wizard")]
[Spells("zoogle", "xclondon")]
public class BlackWizardProvider : IWizardProvider
{
public IWizard CreateWizard()
{
return new BlackWizard();
}
}
}
Of course you'll need to implement the wizards as well.
namespace Wizardry
{
using System;
public class WhiteWizard : IWizard
{
public IMagic GetMagic(string magicWord)
{
throw new NotImplementedException();
}
}
public class BlackWizard : IWizard
{
public IMagic GetMagic(string magicWord)
{
throw new NotImplementedException();
}
}
}
To keep things clean, this code uses a custom NameAttribute and SpellsAttribute as a much cleaner form of exporting metadata than ExportMetadataAttribute:
namespace Wizardry
{
using System;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public abstract class MultipleBaseMetadataAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public abstract class SingletonBaseMetadataAttribute : Attribute
{
}
public sealed class NameAttribute : SingletonBaseMetadataAttribute
{
public NameAttribute(string value) { this.Name = value; }
public string Name { get; private set; }
}
public sealed class SpellsAttribute : MultipleBaseMetadataAttribute
{
public SpellsAttribute(params string[] value) { this.Spells = value; }
public string[] Spells { get; private set; }
}
}
Add another level of indirection. The GetAvailableSpells method isn't really an instance method, since it's the same for all instances. As you pointed you, you can't have an abstract static method, so instead move the type-specific stuff into an instance-based class factory. In the example below, AvailableSpells is a method of the MagicSchool abstract class, which has concrete subclasses BlackMagic, WhiteMagic, etc. The Wizard also has sub-types, but every Wizard can return the MagicSchool that it belongs to, giving you a type-safe, type-independent way to find out what the spells for any given Wizard object are without separate tables or code duplication.
public abstract class MagicSchool
{
public abstract string[] AvailableSpells { get; }
public abstract Wizard CreateWizard();
}
public abstract class Wizard
{
protected Wizard(MagicSchool school)
{
School = school;
}
public abstract Cast(string spell);
MagicSchool School
{
public get;
protected set;
}
}
public class BlackMagic : MagicSchool
{
public override AvailableSpells
{
get
{
return new string[] { "zoogle", "xclondon" };
}
}
public override Wizard CreateWizard()
{
return new BlackWizard(this);
}
}
public class BlackWizard : Wizard
{
public BlackWizard(BlackMagic school)
: base(school)
{
// etc
}
public override Cast(string spell)
{
// etc.
}
}
// continue for other wizard types
First, you should really consider whether you can't bend the rules of not using instances of Wizards to discover their available spells. I find that the prototype pattern can actually be quite useful for this sort of thing.
However, if you really can't do that, you can use nested classes and reflection to discover the available spells that a particular concrete AbsWizard-derivative can cast. Here's an example:
public abstract class AbsWizard
{
public abstract Magic GetMagic(String magicword);
public abstract string[] GetAvalibleSpells();
}
public class WhiteWizard : AbsWizard
{
// organizes all the spells available to the wizard...
public sealed class Spells
{
// NOTE: Spells may be better off as a specific class, rather than as strings.
// Then you could decorate them with a lot of other information (cost, category, etc).
public const string Abracadabra = "Abracadabra";
public const string AlaPeanutButterSandwiches = "APBS";
}
}
public static void CastMagic()
{
Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();
List<Type> wizardTypes = new List<string>();
List<string> avalibleSpells = new List<string>();
Type selectedWizardType;
string selectedSpell;
foreach (Type t in types)
{
if (typeof(AbsWizard).IsAssignableFrom(t))
{
// find a nested class named Spells and search it for public spell definitions
// better yet, use an attribute to decorate which class is the spell lexicon
var spellLexicon = Type.FromName( t.FullName + "+" + "Spells" );
foreach( var spellField in spellLexicon.GetFields() )
// whatever you do with the spells...
}
}
}
There are many ways to improve the above code.
First, you can define your own custom attribute that you can tag on the nested classes of each wizard to identify the spell lexicon.
Second, using strings to define the available spells may end up being a bit limiting. You may find it easier to define a global static list of all available spells (as some kind of class, let's call it Spell). You could then define the available spells of the wizard based off this list, rather than strings.
Third, consider creating an external configuration for this thing rather than embedded, nested classes. It's more flexible and possibly easier to maintain. However, it can be nice to write code like:
WhiteWizard.Spells.Abracadabra.Cast();
Finally, consider creating a static dictionary for each Wizard-derivative that manages the list of available spells so that you can avoid performing reflection (which is expensive) more than once.
Since spells are tied to the type of the wizard, I'd do this through attributes:
[AttributeUsage(AttributeTargets.Class)]
public class SpellsAttribute : Attribute
{
private string[] spells;
public WizardAttribute(params string[] spells)
{
this.spells = spells;
}
public IEnumerable<string> Spells
{
get { return this.spells ?? Enumerable.Empty<string>(); }
}
}
Then you declare a wizard type like this:
[Spells("booblah","zoombar")]
public class WhiteWizard : AbsWizard
{
public override Magic GetMagic(string magicWord) { ... }
}
Then the class that loads wizard types from the assembly can check each wizard class has this attribute and if so makes the type available (or throws an exception).
Does this do what you need? Add each type of wizard to the factory as needed. Wizards will never be instantiated outside of your library, only inside it. For someone outside your library to get a wizard, they make a call to the factory to get those wizards that support a given spell. The factory sets itself up. Just register each new wizard with the factory.
public class Magic
{
}
public abstract class AbsWizard
{
public abstract Magic GetMagic(String magicword);
public abstract string[] GetAvalibleSpells();
internal AbsWizard()
{
}
}
public class WhiteWizard : AbsWizard
{
public override Magic GetMagic(string magicword)
{
return new Magic();
}
public override string[] GetAvalibleSpells()
{
string[] spells = { "booblah", "zoombar" };
return spells;
}
}
public static class WizardFactory
{
private static Dictionary<string, List<AbsWizard>> _spellsList = new Dictionary<string, List<AbsWizard>>();
/// <summary>
/// Take the wizard and add his spells to the global spell pool. Then register him with that spell.
/// </summary>
/// <param name="wizard"></param>
private static void RegisterWizard(AbsWizard wizard)
{
foreach (string s in wizard.GetAvalibleSpells())
{
List<AbsWizard> lst = null;
if (!_spellsList.TryGetValue(s, out lst))
{
_spellsList.Add(s, lst = new List<AbsWizard>());
}
lst.Add(wizard);
}
}
public string[] GetGlobalSpellList()
{
List<string> retval = new List<string>();
foreach (string s in _spellsList.Keys)
{
retval.Add(s);
}
return retval.ToArray<string>();
}
public List<AbsWizard> GetWizardsWithSpell(string spell)
{
List<AbsWizard> retval = null;
_spellsList.TryGetValue(spell, out retval);
return retval;
}
static WizardFactory()
{
RegisterWizard(new WhiteWizard());
}
}
Use a factory class to instantiate your wizards. The factory has a
public static string[] GetSpellsForWizardType(Type wizardType)
method that allows you to determine which spells a wizard can cast. The factory also calls this same method to construct a new wizard instance and set its spell set.