I have and in interface ICalibrationToolsLoader
namespace Utilities.Interfaces
{
public interface ICalibrationToolsLoader
{
string GetDefaultIspFile(string selectedSensorType = null);
IspSectionUiSettings GetIspSectionUiSettings();
List<CalibrationGroup> GetCmcGroupOrder();
}
}
and two classes implements it.
public class Ipu6CalibraitionToolsLoader : ICalibrationToolsLoader
{
private string _selectedSensorType;
public Ipu6CalibraitionToolsLoader(string selectedSensorType)
{
_selectedSensorType = selectedSensorType;
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(GetDefaultIspFile(_selectedSensorType));
InitCmcOrder();
}
public string GetDefaultIspFile(string selectedSensorType = null)
{
string location = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string pathSuffix = null;
switch ((IPU6SensorType)Enum.Parse(typeof(IPU6SensorType), selectedSensorType))
{
case IPU6SensorType.None:
break;
case IPU6SensorType.Bayer:
pathSuffix = "IPUs\\IPU6\\IPU6DefaultsIspFile.xml";
break;
case IPU6SensorType.MD:
pathSuffix = "IPUs\\IPU6\\IPU6MdDefaultsIspFile.xml";
break;
default:
throw new ArgumentOutOfRangeException("selectedSensorType", selectedSensorType, null);
}
if (pathSuffix != null)
{
string path = Path.Combine(location, pathSuffix);
return path;
}
throw new Exception("missing defaultIspFileXml");
}
public void InitCmcOrder()
{
_cmcCalibrationToolsOrder = new List<CalibrationGroup>
{
CalibrationGroup.GeneralDataTools,
CalibrationGroup.SensorAndModuleSettingsTools,
CalibrationGroup.LateralChromaticAberrationTool,
};
}
}
public class Ipu4CalibraitionToolsLoader : ICalibrationToolsLoader
{
public Ipu4CalibraitionToolsLoader()
{
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(GetDefaultIspFile());
InitCmcOrder();
}
public string GetDefaultIspFile(string selectedSensorType = null)
{
string location = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string pathSuffix = "IPUs\\Broxton\\IPU4DefaultsIspFile.xml";
string path = Path.Combine(location, pathSuffix);
return path;
}
public void InitCmcOrder()
{
_cmcCalibrationToolsOrder = new List<CalibrationGroup>
{
CalibrationGroup.GeneralDataTools,
CalibrationGroup.SensorAndModuleSettingsTools,
CalibrationGroup.LateralChromaticAberrationTool,
};
}
}
basically most of the functions are the same however, functions like the constructor and GetDefaultIsp needs to have different implementation.
I tried to use inheritance but calling a virtual function inside the constructor is a big NO NO.
Can you suggest of another way of doing so?
having 2 classes using the same interface however some methods should have different implementation?
I don't want to have another function like Init() which needs to be called after the constructor.
EDIT: Addition of the IoC implementation to solve your issue!
IoC Version
The IoC solution is, in my opinion, way more elegant but probably a little bit more complicated to maintain when you are not used to IoC.
Credits goes to plalx for suggesting it in the comments :D.
// There is no need for an interface anymore (but you can keep it of course)
public class IpuCalibrationToolsLoader
{
private string _selectedSensorType;
private string _ispSectionUiSettings;
private List<CalibrationGroup> _cmcCalibrationToolsOrder;
public IIspFileProvider Provider { get; private set; }
// Notice the internal constructor. No one will be able to create an instance of IpuCalibrationToolsLoader out of your assembly except the factory
internal IpuCalibrationToolsLoader(IIspFileProvider provider, string selectedSensorType = null)
{
this.Provider = provider;
_selectedSensorType = selectedSensorType;
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(provider.GetDefaultIspFile(_selectedSensorType));
this.InitCmcOrder();
}
public void InitCmcOrder()
{
_cmcCalibrationToolsOrder = new List<CalibrationGroup>
{
CalibrationGroup.GeneralDataTools,
CalibrationGroup.SensorAndModuleSettingsTools,
CalibrationGroup.LateralChromaticAberrationTool,
};
}
[..] // Since the Provider is exposed as a properties of your IpuCalibrationClassLoader, there is no need for defining the GetDefaultIspFile methods within this class
}
public interface IIspFileProvider
{
string GetDefaultIspFile(string selectedSensorType = null);
}
public class Ipu6FileProvider : IIspFileProvider
{
public string GetDefaultIspFile(string selectedSensorType = null)
{
string location = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string pathSuffix = null;
switch ((IPU6SensorType)Enum.Parse(typeof(IPU6SensorType), selectedSensorType))
{
case IPU6SensorType.None:
break;
case IPU6SensorType.Bayer:
pathSuffix = "IPUs\\IPU6\\IPU6DefaultsIspFile.xml";
break;
case IPU6SensorType.MD:
pathSuffix = "IPUs\\IPU6\\IPU6MdDefaultsIspFile.xml";
break;
default:
throw new ArgumentOutOfRangeException("selectedSensorType", selectedSensorType, null);
}
if (pathSuffix != null)
{
string path = Path.Combine(location, pathSuffix);
return path;
}
throw new Exception("missing defaultIspFileXml");
}
}
public class Ipu4FileProvider : IIspFileProvider
{
public string GetDefaultIspFile(string selectedSensorType = null)
{
string location = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string pathSuffix = "IPUs\\Broxton\\IPU4DefaultsIspFile.xml";
string path = Path.Combine(location, pathSuffix);
return path;
}
}
public static class IpuCalibrationToolsLoaderFactory
{
public static IpuCalibrationToolsLoader GetIpu4CalibrationToolsLoader()
{
return new IpuCalibrationToolsLoader(new Ipu4FileProvider());
}
public static IpuCalibrationToolsLoader GetIpu6CalibrationToolsLoader(string selectedSensorType)
{
return new IpuCalibrationToolsLoader(new Ipu6FileProvider(), selectedSensorType);
}
}
Inheritance version
Here is the version using an abstract class. An abstract class is a class you cannot instantiate. It only holds some code:
public abstract class BaseCalibrationToolsLoader : ICalibrationToolsLoader
{
public BaseCalibrationToolsLoader()
{
// put here the shared constructor code
_cmcCalibrationToolsOrder = new List<CalibrationGroup>
{
CalibrationGroup.GeneralDataTools,
CalibrationGroup.SensorAndModuleSettingsTools,
CalibrationGroup.LateralChromaticAberrationTool,
};
}
public List<CalibrationGroup> GetCmcGroupOrder()
{
// Put here the shared code among the two implementation
}
// As the implementation is different, you declare the method abstract so you only implement it in the concret classes
public abstract string GetDefaultIspFile(string selectedSensorType = null);
}
Now, you can create your concrete implementation that derived from the abstract class:
public class Ipu4CalibraitionToolsLoader : BaseCalibrationToolsLoader
{
public Ipu4CalibraitionToolsLoader ()
: base() // <- call the protected constructor
{
// put here the specific implementation constructor code
// notice that the constructor of the abstract class will **ALWAYS** be call before this code
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(GetDefaultIspFile());
}
// The GetCmcGroupOrder is already implemented, nothing to do about it
// With the sealed keyword, the method cannot be overriden in another class
public sealed override void GetDefaultIsp(string selectedSensorType = null)
{
// put here the concrete implementation for Ipu4
}
}
public class Ipu6CalibraitionToolsLoader: BaseCalibrationToolsLoader
{
public Ipu6CalibraitionToolsLoader(string selectedSensorType)
: base() // <- call the protected constructor
{
// put here the specific implementation constructor code
// notice that the constructor of the abstract class will **ALWAYS** be call before this code
_selectedSensorType = selectedSensorType;
_ispSectionUiSettings = Serialization.DataContract.Deserialize<IspSectionUiSettings>(GetDefaultIspFile(_selectedSensorType));
}
// The GetCmcGroupOrder is already implemented, nothing to do about it
// With the sealed keyword, the method cannot be overriden in another class
public sealed override void GetDefaultIsp(string selectedSensorType = null)
{
// put here the concrete implementation for Ipu6
}
}
As for the abstract constructor, you can define a virtual method in the abstract class and call it in the concrete implementation, in order to share a part of the code:
public abstract class BaseCalibrationToolsLoader : ICalibrationToolsLoader
{
[..]
// By using the virtual keyword, you allow your method to be overriden in the derived classes
public virtual void PartiallySharedMethod()
{
// Shared implementation
}
[..]
}
And in the concrete implementations:
public class Ipu4CalibraitionToolsLoader : BaseCalibrationToolsLoader
{
[..]
public override void PartiallySharedMethod()
{
// Unlike in the constructor, you can call the base method whenever you want.
// Some specific code can came here
base.PartiallySharedMethod();
// And other specific code can also came here
}
[..]
}
public class Ipu6CalibraitionToolsLoader: BaseCalibrationToolsLoader
{
[..]
public override void PartiallySharedMethod()
{
// Unlike in the constructor, you can call the base method whenever you want.
// Some specific code can came here
base.PartiallySharedMethod();
// And other specific code can also came here
}
[..]
}
Related
So this is a rather specific question.
Assuming I have a set of classes, which all generate a different string. The only thing in common between these, is that they require the same "header" in the string.
I have decided to create a base class for generating the header, which they all derive from.
internal abstract class StringBase
{
public virtual string WriteString()
{
var headerString = "header";
return headerString;
}
}
Now for a derived class, which must include the header, but also add its own subsequent string.
internal class DerivedString : StringBase
{
public override string WriteString()
{
var derivedString = // How would I best add the header and append more to it?
return derivedString;
}
}
Overriding it like this would obviously overwrite whatever the base WriteString() does, so how would I make sure I get it? Could it be something like adding a non-virtual method in the base, which then calls the virtual method with the header string as a parameter?
internal abstract class StringBase
{
public void WriteHeader()
{
var headerString = "header";
WriteString(headerString);
}
public virtual string WriteString(string headerString)
{
var derivedString = headerString.Append("whateverString");
return string.empty;
}
}
internal class DerivedString : StringBase
{
public override string WriteString(string headerString)
{
var derivedString = headerString.Append("whateverString");
return derivedString;
}
}
You could use the base keyword for this, like so:
internal class DerivedString : StringBase
{
public override string WriteString(string headerString)
{
var derivedString = base.WriteString().Append("whateverString");
return derivedString;
}
}
One way to make it work is by using a private field in base class:
internal abstract class StringBase
{
private string headerString = "header";
public virtual string WriteString(String input=null)
{
return String.IsNullOrEmpty(input) ? headerString : headerString + input;
}
}
and then you can call the method from derived classes by passing in the parameter.
As i am learning through design pattern concept and also wanted to implement the payment modules in my project using the proper design pattern. So for that I have created some sample code.
Currently I have two concrete implementation for the payment PayPal and Credit Card. But the concrete implementation will be added further on the project.
Payment Service
public interface IPaymentService
{
void MakePayment<T>(T type) where T : class;
}
Credit Card and Pay Pal Service
public class CreditCardPayment : IPaymentService
{
public void MakePayment<T>(T type) where T : class
{
var creditCardModel = (CreditCardModel)(object)type;
//Implementation CreditCardPayment
}
}
class PayPalPayment : IPaymentService
{
public void MakePayment<T>(T type) where T : class
{
var payPalModel = (PayPalModel)(object)type;
//Further Implementation will goes here
}
}
Client Code Implementation
var obj = GetPaymentOption(payType);
obj.MakePayment<PayPalModel>(payPalModel);
Get Payment Option
private static IPaymentService GetPaymentOption(PaymentType paymentType)
{
IPaymentService paymentService = null;
switch (paymentType)
{
case PaymentType.PayPalPayment:
paymentService = new PayPalPayment();
break;
case PaymentType.CreditCardPayment:
paymentService = new CreditCardPayment();
break;
default:
break;
}
return paymentService;
}
I thought of implementing this modules using strategy design pattern, and I got deviated from Strategy and ended up doing this way.
Is this a proper way for creating the payment modules. Is there a more better approach of solving this scenario. Is this a design pattern?
Edited:
Client Code:
static void Main(string[] args)
{
PaymentStrategy paymentStrategy = null;
paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)1));
paymentStrategy.Pay<PayPalModel>(new PayPalModel() { UserName = "", Password = "" });
paymentStrategy = new PaymentStrategy(GetPaymentOption((PaymentType)2));
paymentStrategy.Pay<CreditCardModel>(
new CreditCardModel()
{
CardHolderName = "Aakash"
});
Console.ReadLine();
}
Strategy:
public class PaymentStrategy
{
private readonly IPaymentService paymentService;
public PaymentStrategy(IPaymentService paymentService)
{
this.paymentService = paymentService;
}
public void Pay<T>(T type) where T : class
{
paymentService.MakePayment(type);
}
}
Does this update inlines with the Strategy Pattern?
One major drawback of using an abstract factory for this is the fact that it contains a switch case statement. That inherently means if you want to add a payment service, you have to update the code in the factory class. This is a violation of the Open-Closed Principal which states that entities should be open for extension but closed for modification.
Note that using an Enum to switch between payment providers is also problematic for the same reason. This means that the list of services would have to change every time a payment service is added or removed. Even worse, a payment service can be removed from the strategy, but still be an Enum symbol for it even though it isn't valid.
On the other hand, using a strategy pattern doesn't require a switch case statement. As a result, there are no changes to existing classes when you add or remove a payment service. This, and the fact that the number of payment options will likely be capped at a small double-digit number makes the strategy pattern a better fit for this scenario.
Interfaces
// Empty interface just to ensure that we get a compile
// error if we pass a model that does not belong to our
// payment system.
public interface IPaymentModel { }
public interface IPaymentService
{
void MakePayment<T>(T model) where T : IPaymentModel;
bool AppliesTo(Type provider);
}
public interface IPaymentStrategy
{
void MakePayment<T>(T model) where T : IPaymentModel;
}
Models
public class CreditCardModel : IPaymentModel
{
public string CardHolderName { get; set; }
public string CardNumber { get; set; }
public int ExpirtationMonth { get; set; }
public int ExpirationYear { get; set; }
}
public class PayPalModel : IPaymentModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
Payment Service Abstraction
Here is an abstract class that is used to hide the ugly details of casting to the concrete model type from the IPaymentService implementations.
public abstract class PaymentService<TModel> : IPaymentService
where TModel : IPaymentModel
{
public virtual bool AppliesTo(Type provider)
{
return typeof(TModel).Equals(provider);
}
public void MakePayment<T>(T model) where T : IPaymentModel
{
MakePayment((TModel)(object)model);
}
protected abstract void MakePayment(TModel model);
}
Payment Service Implementations
public class CreditCardPayment : PaymentService<CreditCardModel>
{
protected override void MakePayment(CreditCardModel model)
{
//Implementation CreditCardPayment
}
}
public class PayPalPayment : PaymentService<PayPalModel>
{
protected override void MakePayment(PayPalModel model)
{
//Implementation PayPalPayment
}
}
Payment Strategy
Here is the class that ties it all together. Its main purpose is to provide the selection functionality of the payment service based on the type of model passed. But unlike other examples here, it loosely couples the IPaymentService implementations so they are not directly referenced here. This means without changing the design, payment providers can be added or removed.
public class PaymentStrategy : IPaymentStrategy
{
private readonly IEnumerable<IPaymentService> paymentServices;
public PaymentStrategy(IEnumerable<IPaymentService> paymentServices)
{
this.paymentServices = paymentServices ?? throw new ArgumentNullException(nameof(paymentServices));
}
public void MakePayment<T>(T model) where T : IPaymentModel
{
GetPaymentService(model).MakePayment(model);
}
private IPaymentService GetPaymentService<T>(T model) where T : IPaymentModel
{
var result = paymentServices.FirstOrDefault(p => p.AppliesTo(model.GetType()));
if (result == null)
{
throw new InvalidOperationException(
$"Payment service for {model.GetType().ToString()} not registered.");
}
return result;
}
}
Usage
// I am showing this in code, but you would normally
// do this with your DI container in your composition
// root, and the instance would be created by injecting
// it somewhere.
var paymentStrategy = new PaymentStrategy(
new IPaymentService[]
{
new CreditCardPayment(), // <-- inject any dependencies here
new PayPalPayment() // <-- inject any dependencies here
});
// Then once it is injected, you simply do this...
var cc = new CreditCardModel() { CardHolderName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(cc);
// Or this...
var pp = new PayPalModel() { UserName = "Bob" /* Set other properties... */ };
paymentStrategy.MakePayment(pp);
Additional References:
Dependency Injection Unity - Conditional Resolving
Factory method with DI and IoC
This is one approach you could take. There's not a lot to go on from your source, and I'd really reconsider having MakePayment a void instead of something like an IPayResult.
public interface IPayModel { } // Worth investigating into common shared methods and properties for this
public interface IPaymentService
{
void MakePayment(IPayModel payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
void MakePayment(T payModel); // Void here? Is the status of the payment saved on the concrete pay model? Why not an IPayResult?
}
public class CreditCardModel : IPayModel
{
public string CardHolderName { get; set; }
}
public class PayPalModel : IPayModel
{
public string UserName { get; set; }
public string Password { get; set; }
}
public class CreditCardPayment : IPaymentService<CreditCardModel>
{
public void MakePayment(CreditCardModel payModel)
{
//Implmentation CreditCardPayment
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as CreditCardModel);
}
}
public class PayPalPayment : IPaymentService<PayPalModel>
{
public void MakePayment(PayPalModel payModel)
{
//Implmentation PayPalPayment
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as PayPalModel);
}
}
public enum PaymentType
{
PayPalPayment = 1,
CreditCardPayment = 2
}
So following your implementation approach, it could look something like:
static class Program
{
static void Main(object[] args)
{
IPaymentService paymentStrategy = null;
paymentStrategy = GetPaymentOption((PaymentType)1);
paymentStrategy.MakePayment(new PayPalModel { UserName = "", Password = "" });
paymentStrategy = GetPaymentOption((PaymentType)2);
paymentStrategy.MakePayment(new CreditCardModel { CardHolderName = "Aakash" });
Console.ReadLine();
}
private static IPaymentService GetPaymentOption(PaymentType paymentType)
{
switch (paymentType)
{
case PaymentType.PayPalPayment:
return new PayPalPayment();
case PaymentType.CreditCardPayment:
return new CreditCardPayment();
default:
throw new NotSupportedException($"Payment Type '{paymentType.ToString()}' Not Supported");
}
}
}
I also think for a strategy/factory pattern approach, manually creating an IPayModel type doesn't make much sense. Therefore you could expand the IPaymentService as an IPayModel factory:
public interface IPaymentService
{
IPayModel CreatePayModel();
void MakePayment(IPayModel payModel);
}
public interface IPaymentService<T> : IPaymentService where T : IPayModel
{
new T CreatePayModel();
void MakePayment(T payModel);
}
public class CreditCardPayment : IPaymentService<CreditCardModel>
{
public CreditCardModel CreatePayModel()
{
return new CreditCardModel();
}
public void MakePayment(CreditCardModel payModel)
{
//Implmentation CreditCardPayment
}
IPayModel IPaymentService.CreatePayModel()
{
return CreatePayModel();
}
void IPaymentService.MakePayment(IPayModel payModel)
{
MakePayment(payModel as CreditCardModel);
}
}
Usage would then be:
IPaymentService paymentStrategy = null;
paymentStrategy = GetPaymentOption((PaymentType)1);
var payModel = (PayPalModel)paymentStrategy.CreatePayModel();
payModel.UserName = "";
payModel.Password = "";
paymentStrategy.MakePayment(payModel);
Your code is basically using the factory pattern. This is a good way to handle more than one method of payment
http://www.dotnettricks.com/learn/designpatterns/factory-method-design-pattern-dotnet
I would like to perform testing for below abstract Streaming class which has two virtual methods that are overridden in the Asset class in same project. Here the SerializeBinary() method converts an object into binary streams and DeserializeFromBinary() method does the opposite of SerializeBinary().
How to write test class for comparing both using Moq?
I go through from here:
This is part of my code:
Streaming class:
public abstract class Streaming
{
private static int _streamingIDExponent = 41;
public const string MonthLookup = "ABCDEFGHIJK";
public const string ExpiryStringFormat = "ddMMMyyyy";
public const double DefaultTicksPerPoint = 3;
private long _StreamingID;
private int _minQty = DefaultMinimumQty;
public virtual void SerializeBinary(BinaryStreamWriter binaryStreamWriter)
{
binaryStreamWriter.Write(_StreamingID);
binaryStreamWriter.Write(_ex_StreamingID);
binaryStreamWriter.Write(_minQty);
binaryStreamWriter.Write(_extendedProperties.Count);
foreach (KeyValuePair<StreamingPropertyName, StreamingProperty> dictionaryEntry in _extendedProperties)
{
dictionaryEntry.Value.SerializeBinary(binaryStreamWriter);
}
}
public virtual bool DeserializeFromBinary(BinaryStreamReader binaryStreamReader, out string errorString)
{
errorString = string.Empty;
try
{
_StreamingID = binaryStreamReader.ReadInt64();
_exStreamingID = binaryStreamReader.ReadInt64();
_minQty = binaryStreamReader.ReadInt32();
}
catch (Exception oEx)
{
errorString = oEx.Message;
}
return string.IsNullOrEmpty(errorString);
}
Asset class:
public class Asset : Streaming
{
public override void SerializeBinary(BinaryStreamWriter binaryStreamWriter)
{
base.SerializeBinary(binaryStreamWriter);
}
public override bool DeserializeFromBinary(BinaryStreamReader binaryStreamReader, out string errorString)
{
if (!base.DeserializeFromBinary(binaryStreamReader, out errorString))
return false;
try
{
return true;
}
catch (Exception oEx)
{
errorString = oEx.Message;
return false;
}
}
}
you can create a new Mock of your Streaming class like this:
var streamingMock = new Mock<Streaming> { CallBase = true };
The call base is important because it will then execute the implemented code in your concrete class.
Then you can call the methods via the Object property:
streamingMock.Object.SerializeBinary(...);
Hope this helps
There's no good way to test the interaction between Asset and Streaming with Moq in your current implementation. However, if you're willing to change the implementation of the classes just a bit, you can get it done. Basically, you'll want to move the logic of the Streaming class's methods into new methods, and you can then mock those.
public abstract class Streaming
{
public virtual void SerializeBinaryCore(BinaryStreamWriter writer)
{
// put the logic from your original SerializeBinary method here...
}
public virtual bool DeserializeFromBinaryCore(BinaryStreamReader reader, out string errorMessage)
{
// put the logic from your original DeserializeFromBinary method here...
}
public abstract void SerializeBinary(BinaryStreamWriter writer);
public abstract bool DeserializeFromBinary(BinaryStreamReader reader, out string errorMessage);
}
And then tweak your Asset class as follows:
public class Asset : Streaming
{
public override void SerializeBinary(BinaryStreamWriter writer)
{
SerializeBinaryCore(writer);
}
public override void DeserializeFromBinary(BinaryStreamReader reader, out string errorMessage)
{
var result = DeserializeFromBinaryCore(reader, out errorMessage);
// put the rest of your Asset deserialization logic here...
}
}
In your test, you need to create a Mock<Asset> { CallBase = true }, and then create setups for the SerializeBinaryCore and DeserializeFromBinaryCore methods.
I have say 3 classes, Animal, Cat & Dog.
// calling code
var x = new Animal("Rex"); // would like this to return a dog type
var x = new Animal("Mittens"); // would like this to return a cat type
if(x.GetType() == typeof(Dog))
{
x.Bark();
}
else
{
x.Meow();
}
class Animal
{
public Animal(string name)
{
// check against some list of dog names ... find rex
// return Animal of type Dog.
// if not...
// check against some list of cat names ... find mittens
// return Animal of type Cat.
}
}
Is this possible somehow? If not is there something similar I can do?
What you are looking for is either a 'virtual constructor' (not possibe in C#) or the Factory pattern.
class Animal
{
// Factory method
public static Animal Create(string name)
{
Animal animal = null;
... // some logic based on 'name'
animal = new Zebra();
return animal;
}
}
The Factory method can also be placed in another (Factory) class. That gives better decoupling etc.
No. Basically the right fix is to use a static method which can create an instance of the right type:
var x = Animal.ForName("Rex");
var x = Animal.ForName("Mittens");
...
public abstract class Animal
{
public static Animal ForName(string name)
{
if (dogNames.Contains(name))
{
return new Dog(name);
}
else
{
return new Cat(name);
}
}
}
Or this could be an instance method in an AnimalFactory type (or whatever). That would be a more extensible approach - the factory could implement an interface, for example, and could be injected into the class which needed to create the instances. It really depends on the context though - sometimes that approach is overkill.
Basically, a new Foo(...) call always creates an instance of exactly Foo. Whereas a static method declared with a return type of Foo can return a reference to any type which is compatible with Foo.
No I dont think it is possible in the way that you want.
You could create a static class that has a method that returns an animal based on a name e.g.
static Animal CreateAnimal(string name)
{
if(catList.Contains(name))
return new Cat(name");
else if(dogList.Contains(name))
return new Dog(name);
return null;
}
The other answers show that you need to use a factory pattern but I wanted to give you a more "practical" example of how you would do it. I did exactly what you where doing, however I was working with the EPL2 printer language. When I saw X I needed to create a instance of class Rectangle, when I saw A I needed to create a instance of class Text.
(I wrote this a long time ago so I am sure some of the things I did could be improved upon).
public partial class Epl2CommandFactory
{
#region Singelton pattern
private static volatile Epl2CommandFactory m_instance;
private static object m_syncRoot = new object();
public static Epl2CommandFactory Instance
{
get
{
if (m_instance == null)
{
lock (m_syncRoot)
{
if (m_instance == null)
{
m_instance = new Epl2CommandFactory();
}
}
}
return m_instance;
}
}
#endregion
#region Constructor
private Epl2CommandFactory()
{
m_generalCommands = new Dictionary<string, Type>();
Initialize();
}
#endregion
#region Variables
private Dictionary<string, Type> m_generalCommands;
private Assembly m_asm;
#endregion
#region Helpers
private void Initialize()
{
Assembly asm = Assembly.GetAssembly(GetType());
Type[] allTypes = asm.GetTypes();
foreach (Type type in allTypes)
{
// Only scan classes that are not abstract
if (type.IsClass && !type.IsAbstract)
{
// If a class implements the IEpl2FactoryProduct interface,
// which allows retrieval of the product class key...
Type iEpl2FactoryProduct = type.GetInterface("IEpl2GeneralFactoryProduct");
if (iEpl2FactoryProduct != null)
{
// Create a temporary instance of that class...
object inst = asm.CreateInstance(type.FullName);
if (inst != null)
{
// And generate the product classes key
IEpl2GeneralFactoryProduct keyDesc = (IEpl2GeneralFactoryProduct)inst;
string key = keyDesc.GetFactoryKey();
m_generalCommands.Add(key, type);
inst = null;
}
}
}
}
m_asm = asm;
}
#endregion
#region Methods
public IEpl2Command CreateEpl2Command(string command)
{
if (command == null)
throw new NullReferenceException("Invalid command supplied, must be " +
"non-null.");
Type type;
if (!m_generalCommands.TryGetValue(command.Substring(0, 2), out type))
m_generalCommands.TryGetValue(command.Substring(0, 1), out type);
if (type != default(Type))
{
object inst = m_asm.CreateInstance(type.FullName, true,
BindingFlags.CreateInstance,
null, null, null, null);
if (inst == null)
throw new NullReferenceException("Null product instance. " +
"Unable to create necessary product class.");
IEpl2Command prod = (IEpl2Command)inst;
prod.CommandString = command;
return prod;
}
else
{
return null;
}
}
#endregion
}
The way the code works is I use the singleton pattern to create a factory class so people can call var command = Epl2CommandFactory.Instance.CreateEpl2Command("..."); passing in the EPL2 command string and it returns a instance of the class that represents that specific class.
During initialization I use reflection to find classes that support the IEpl2GeneralFactoryProduct interface, if the class supports the interface the factory stores the one or two letter code representing the printer command in a dictionary of types.
When you try to create the command the factory looks up the printer command in the dictionary and creates the correct class, it then passes the full command string on to that class for further processing.
Here is a copy of a command class and it's parents if you wanted to see it
Rectangle:
[XmlInclude(typeof(Rectangle))]
public abstract partial class Epl2CommandBase { }
/// <summary>
/// Use this command to draw a box shape.
/// </summary>
public class Rectangle : DrawableItemBase, IEpl2GeneralFactoryProduct
{
#region Constructors
public Rectangle() : base() { }
public Rectangle(Point startingLocation, int horozontalEndPosition, int verticalEndPosition)
: base(startingLocation)
{
HorizontalEndPosition = horozontalEndPosition;
VerticalEndPosition = verticalEndPosition;
}
public Rectangle(int x, int y, int lineThickness, int horozontalEndPosition, int verticalEndPosition)
: base(x, y)
{
LineThickness = lineThickness;
HorizontalEndPosition = horozontalEndPosition;
VerticalEndPosition = verticalEndPosition;
}
#endregion
#region Properties
[XmlIgnore]
public int LineThickness { get; set; }
[XmlIgnore]
public int HorizontalEndPosition {get; set;}
[XmlIgnore]
public int VerticalEndPosition { get; set; }
public override string CommandString
{
get
{
return String.Format("X{0},{1},{2},{3},{4}", X, Y, LineThickness, HorizontalEndPosition, VerticalEndPosition);
}
set
{
GenerateCommandFromText(value);
}
}
#endregion
#region Helpers
private void GenerateCommandFromText(string command)
{
if (!command.StartsWith(GetFactoryKey()))
throw new ArgumentException("Command must begin with " + GetFactoryKey());
string[] commands = command.Substring(1).Split(',');
this.X = int.Parse(commands[0]);
this.Y = int.Parse(commands[1]);
this.LineThickness = int.Parse(commands[2]);
this.HorizontalEndPosition = int.Parse(commands[3]);
this.VerticalEndPosition = int.Parse(commands[4]);
}
#endregion
#region Members
public override void Paint(Graphics g, Image buffer)
{
using (Pen p = new Pen(Color.Black, LineThickness))
{
g.DrawRectangle(p, new System.Drawing.Rectangle(X, Y, HorizontalEndPosition - X, VerticalEndPosition - Y));
}
}
public string GetFactoryKey()
{
return "X";
}
#endregion
}
DrawableItemBase:
public abstract class DrawableItemBase : Epl2CommandBase, IDrawableCommand
{
protected DrawableItemBase()
{
Location = new Point();
}
protected DrawableItemBase(Point location)
{
Location = location;
}
protected DrawableItemBase(int x, int y)
{
Location = new Point();
X = x;
Y = y;
}
private Point _Location;
[XmlIgnore]
public virtual Point Location
{
get { return _Location; }
set { _Location = value; }
}
[XmlIgnore]
public int X
{
get { return _Location.X; }
set { _Location.X = value; }
}
[XmlIgnore]
public int Y
{
get { return _Location.Y; }
set { _Location.Y = value; }
}
abstract public void Paint(Graphics g, Image buffer);
}
Epl2CommandBase:
public abstract partial class Epl2CommandBase : IEpl2Command
{
protected Epl2CommandBase() { }
public virtual byte[] GenerateByteCommand()
{
return Encoding.ASCII.GetBytes(CommandString + '\n');
}
public abstract string CommandString { get; set; }
}
Various Interfaces:
public interface IEpl2GeneralFactoryProduct
{
string GetFactoryKey();
}
public interface IEpl2Command
{
string CommandString { get; set; }
}
public interface IDrawableCommand : IEpl2Command
{
void Paint(System.Drawing.Graphics g, System.Drawing.Image buffer);
}
I need to have a wrapper class that exposes some properties of my entity class called ProfileEntity.
I tried doing it by deriving from this entity and then creating properties that return specific entity properties, but it says I cannot cast from ProfileEntity to ProfileEntityWrapper.
When I try to put the return values of a method that returns a 'ProfileEntity' into the wrapper I get the above error.
How do I create such a wrapper class that is castable?
Example
class ProfileEntityWrapper : ProfileEntity
{
public string Name
{
get
{
return this.ProfileEntityName;
}
}
}
public class Someclass
{
public ProfileEntity SomeMethod()
{
return ProfileEntity; // example of method returning this object
}
}
public class SomeOtherlClass
{
SomeClass sc = new SomeClass();
public void DoSomething()
{
ProfileEntityWrapper ew = (ProfileEntityWrapper)sc.SomeMethod(); // Cannot do this cast!!!
}
}
You cannot cast an object of ProfileEntity to ProfileEntityWrapper.
var entity = new ProfileEntity(); // this object is only of type ProfileEntity
var wrapper = new ProfileEntityWrapper(); // this object can be used as both ProfileEntityWrapper and ProfileEntity
You probably want to return a ProfileEntityWrapper in SomeMethod():
public class Someclass
{
public ProfileEntity SomeMethod()
{
return new ProfileEntityWrapper(); // it's legal to return a ProfileEntity
}
}
No, that is not possible.
To accomplish this problem you can maybe try this one:
public class ProfileEntity
{
public string ProfileEntityName { get; set; }
}
public class ProfileEntityWrapper
{
public ProfileEntityWrapper(ProfileEntity entity)
{
Entity = entity;
}
public ProfileEntity Entity { get; private set; }
public string Name
{
get
{
return Entity.ProfileEntityName;
}
}
}
public class SomeClass
{
public ProfileEntity SomeMethod()
{
// example of method returning this object
ProfileEntity temp = new ProfileEntity();
return temp;
}
}
public class SomeOtherClass
{
SomeClass sc = new SomeClass();
public void DoSomething()
{
//Create a new Wrapper for an existing Entity
ProfileEntityWrapper ew = new ProfileEntityWrapper(sc.SomeMethod());
}
}
If you are allowed to edit the ProfileEntity class, or if the ProfileEntity class is a generated partial class, you could add an interface instead of using a wrapper. You wouldn't need to do any casting with an interface either. Example:
public interface IProfile
{
string Name { get; }
}
public partial class ProfileEntity : IProfile
{
public string Name
{
get
{
return this.ProfileEntityName;
}
}
}
public class SomeClass
{
public ProfileEntity SomeMethod()
{
return ProfileEntity;
}
}
public class SomeOtherClass
{
SomeClass sc = new SomeClass();
public void DoSomething()
{
IProfile ew = sc.SomeMethod();
}
}
The IProfile instance will only provide access to the Name property.
This's no correct code from polymorphism aspect.
If we will take the famous polymorphism example when there're base Shape class and Circle, Polygon and Rectangle classes that extend the Shape class, your code will try to cast some shape into circle and as you understand this's invalid casting operation.
So to make this code work you must be sure that SomeClass.SomeMethod() will return instance of ProfileEntityWrapper or perform type check before the casting, like this:
ProfileEntity temp = sc.SomeMethod();
if(temp is ProfileEntityWrapper)
ProfileEntityWrapper ew = (ProfileEntityWrapper) temp;