I've seen this asked, but the standard answer is
An interface is a way to define a contract to interact with an object.
This is all and well, but I'm in need of a way for a class to describe itself to allow its creation. Specifically, I have interface ITicket which defines an object responsible for selling/buying assets. Different implementations require different parameters. My reflex would have been to do something that looks like:
public interface ITicket{
static List<TicketOptions> GetAvailableOptions();
}
public class TicketOption{
public string Label { get; set; }
public string Type { get; set; }
public string Default { get; set; }
}
Then I could have selected an implementation of ITicket in my GUI, and looped over the parameters to create an interface with IntegerUpDown controls for integers, DecimalUpDown controls for decimals and dropdown boxes for Enums.
Alas, C# won't let me. So here I am, looking for an equivalent. Surely there must be a pattern to let me define a contract to interact with a class without an instance?
Edit: Getting into more details...
My C# application loads IronPython scripts. It scans the /Scripts folder and assumes every python file in there contains a class called Ticket implementing ITicket.
I would like to get a list of available parameters for every script to build an interface. This way developpers can create python scripts that they drop into a folder that add new complex behavior without re-compiling the application.
Everything works well, except automatically (and cleanly) knowing what parameters are needed.
Related
I've been working on learning how to use interfaces correctly in c# and I think I mostly understand how they should be used but still feel confused about certain things.
I want to create a program that will create a CSV from Sales Orders or Invoices. Since they are both very similar I figured I could create an IDocument interface that could be used to make a CSV document.
class Invoice : IDocument
{
public Address billingAddress { get; set; }
public Address shippingAddress { get; set; }
public Customer customer { get; set; }
public List<DocumentLine> lines { get; set; }
// other class specific info for invoice goes here
}
I can create a method CreateCSV(IDocument) but how would I deal with the few fields that differ from Sales Orders and Invoices? Is this a bad use of interfaces?
You don't inherit interfaces, you implement them; and in this case the interface is an abstraction; it says "all things that implement this interface have the following common characteristics (properties, methods, etc)"
In your case, you have found that in fact Invoices and Sales Orders don't quite share the exact same characteristics.
Therefore from the point of view of representing them in CSV format, it's not a great abstraction (although for other things, like calculating the value of the document, it's an excellent one)
There are a number of ways you can work around this though, here are two (of many)
Delegate the work to the classes
You can declare an ICanDoCSVToo interface that returns the document in some kind of structure that represents CSV (let's say a CSVFormat class that wraps a collection of Fields and Values).
Then you can implement this on both Invoices and Sales Orders, specifically for those use cases, and when you want to turn either of them into CSV format, you pass them by the ICanDoCSVToo interface.
However I personally don't like that as you don't really want your Business Logic mixed up with your export/formatting logic - that's a violation of the SRP. Note you can achieve the same effect with abstract classes but ultimately it's the same concept - you allow someone to tell the class that knows about itself, to do the work.
Delegate the work to specialised objects via a factory
You can also create a Factory class - let's say a CSVFormatterFactory, which given an IDocument object figures out which formatter to return - here is a simple example
public class CSVFormatterLibrary
{
public ICSVFormatter GetFormatter(IDocument document)
{
//we've added DocType to IDocument to identify the document type.
if(document.DocType==DocumentTypes.Invoice)
{
return new InvoiceCSVFormatter(document);
}
if (document.DocType==DocumentTypes.SalesOrders)
{
return new SalesOrderCSVFormatter(document);
}
//And so on
}
}
In reality, you'd might make this generic and use an IOC library to worry about which concrete implementation you would return, but it's the same concept.
The individual formatters themselves can then cast the IDocument to the correct concrete type, and then do whatever is specifically required to produce a CSV representation of that specialised type.
There are other ways to handle this as well, but the factory option is reasonably simple and should get you up and running whilst you consider the other options.
I am generating classes from XSD and need to populate the classes to serialize to xml.
I have different classes, containing all the info that goes into the classes generated.
The problem is that the generated classes come in versions, and properties in those classes are other classes in the same version.
class LocalData
{
public MyClass property { get; set; }
}
class XmlVersion1
{
public MyClassV1 property { get; set; }
}
class XmlVersion2
{
public MyClassV2 property { get; set; }
public MyClassXV2 newProperty { get; set; }
}
The data in MyClassV1 and V2 are basically the same, so the same code can be used.
I wanted to make a factory that just took the LocalData class and any of the versioned classes and populated the data in the versioned class, but I run into a problem when I want to do property = new MyClassVx, because the factory does not know which version it's supposed to create.
I could do
if (parameter is MyClassV1)
paramter.MyClassV1 = new MyClassV1
and so on, but that is a LOT of code.
This is for generating xml messages that are specified by an external company, and they come in different versions, and we have to be able to serialize and deserialize the content into our internal system.
We have not found a solution to this specific issue and chose to use AutoMapper which seems to solve our problem in a different way.
We made a tool that takes the generated classes and creates the mapping classes needed for AutoMapper through assembly. If you have large generated classes you could do this as well. We can now create thousands of lines of code needed to map classes. It solves an issue we had when mapping types of 'object' to specific classes. I don't know if it's helpful but there it is.
Idea is very simple. Factory will not care about version. But newer clients will always support old versions' features. If version 0.5 has a method to receive orders list (for example this is a shopping app) version 0.6 also should have same method. We have same structure and we are doing this way.
I need to create some custom attributes, to be used for my reflection functions.
Here is the usecase, as I see it:
the user creates some class and marks it with my special attribute ([ImportantAttribute] for example)
then the user does something with functions from my library. Those functions find classes with [ImportantAttribute] and do something with them
The main problem is that functions in my library expects, that classes wich was marked with [ImportantAttribute] inherit my interface (IMyInterface for example)
Is there any way to let user know if he mark his class with [ImportantAttribute] and forget to inherit IMyInterface during compilation, not in run time. Some way to specify that this attribute is only for classes that inherit IMyInterface.
Same with attributes for properties and fields.
Is there any way to let user know if he mark his class with
[ImportantAttribute] and forget to inherit IMyInterface during
compilation, not in run time
Simple answer: no, this is not possible. Not at compile-time. You can check this at runtime though using reflection.
The best you could do with attributes at compile-time (except some special system attributes such as Obsolete but which are directly incorporated into the compiler) is specify their usage with the [AttributeUsage] attribute.
I've used the strategy you mention in a couple of the frameworks I've built with good success. One such example is for providing metadata to a plug-in infrastructure:
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false, Inherited=false)]
public class PluginAttribute : Attribute
{
public string DisplayName { get; set; }
public string Description { get; set; }
public string Version { get; set; }
}
public interface IPlug
{
void Run(IWork work);
}
[Plugin(DisplayName="Sample Plugin", Description="Some Sample Plugin")]
public class SamplePlug : IPlug
{
public void Run(IWork work) { ... }
}
Doing so allows me to figure out information about plug-ins without having to instantiate them and read metadata properties.
In my experience in doing so, the only way I've found to enforce that both requirements are met is to perform runtime checks and make sure it is bold and <blink>blinking</blink> in the documentation. It is far from optimal but it is the best that can be done (that I've found). Then again I'm sure there is a better way to go about handling this but so far this has been pretty solid for me.
I have a class which is has tons of properties. Most of them are of custom types. I want to get all those properties, type of whose interface is same.
Public class abc:IamLegend
{
few properties
}
public class def:IamLegend
{
few properties
}
public class on_which_iamworking
{
public abc propabc{ get; set; }
public def propdef{ get; set; }
public someothertype propother{ get; set; }
}
I want something which returns propabc and propdef.
I know how to do it using reflection, but I am looking for another way.
I am working on c# 4.0
Thanks
I am afraid that this is not possible at runtime without using reflection. That's what reflection is designed for.
The main problem of reflection is that it is slow. If you don't want to use reflection only because of it's slowness, you could make caching of your property list in some static property or class. I used this tecknique widely in similar problems and there wasn't any problems with perfomance.
If you have holy war against reflection, you could create a special util that parses C# file (or builds your prokects, loads output assembly and use reflection, but only before build, not in run-time), finds needed properties and writes it into autogenerated file (maybe also C# code file) as static-class array-property initializer. And call that util on pre-build event of your project. Then you'll get all needed properties completely without reflections =) (but I wouldn't do that)
Well, there's two ways:
1/
return new List<string> { "propabc", "propdev" };
2/ Reflection :P
If you need to retrieve the list of properties many times and are afraid of the performance impact, compute the list only once and store it in a static property (as the list of properties of a class won't change during runtime).
There is an alternative approach for components. It is TypeDescriptor for classes that implement IComponent. I believe that is used by WPF.
Up to now, I've always decorated my .NET classes that I want to use from VB6 with the [AutoDual] attribute. The point was to gain Intellisense on .NET objects in the VB6 environment. However, the other day I googled AutoDual and the first answer is 'Do Not Use AutoDual'.
I've looked for coherent explanation of why I shouldn't use it, but could not find it.
Can someone here explain it?
I found a reliable way to both provide Intellisense for .NET objects in VB6, while at the same time not breaking the interface. The key is to mark each public method/property in the interface with DispatchID. Then the class must inherit from this interface - in the manner below.
[Guid("BE5E0B60-F855-478E-9BE2-AA9FD945F177")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICriteria
{
[DispId(1)]
int ID { get; set; }
[DispId(2)]
string RateCardName { get; set; }
[DispId(3)]
string ElectionType { get; set; }
}
[Guid("3023F3F0-204C-411F-86CB-E6730B5F186B")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("MyNameSpace.Criteria")]
public class Criteria : ICriteria
{
public int ID { get; set; }
public string RateCardName { get; set; }
public string ElectionType { get; set; }
}
What the dispatch ID gives you is the ability to move around items in the class, plus you can now add new things to the class and not break the binary compatibility.
I think this sums it up:
Types that use a dual interface allow
clients to bind to a specific
interface layout. Any changes in a
future version to the layout of the
type or any base types will break COM
clients that bind to the interface. By
default, if the
ClassInterfaceAttribute attribute is
not specified, a dispatch-only
interface is used.
http://msdn.microsoft.com/en-us/library/ms182205.aspx
It increases the possibility that changing something in that class with the auto dual attribute will break someone else's code when the class is changed. If gives the consumer the ability to do something that will quite possibly cause them issues in the future.
The next option is ClassInterfaceType.AutoDual. This is the quick and dirty way to get early binding support as well (and make the methods show up in VB6 IntelliSense). But it's also easy to break compatibility, by changing the order of methods or adding new overloads. Avoid using AutoDual.
http://www.dotnetinterop.com/faq/?q=ClassInterface
I finally found the link that talks about what is going on with AutoDual and how it works:
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/7fa723e4-f884-41dd-9405-1f68afc72597
The warning against AutoDual isn't the
fact that dual interfaces is bad but
the fact that it auto-generates the
COM interface for you. That is bad.
Each time the COM interface has to be
regenerated you'll get a new GUID and
potentially new members. If the GUID
changes then you get a brand new
interface/class as far as COM is
concerned. For early binding you'd
have to rebuild the clients each time
the interface was regenerated. The
preferred approach is to define the
COM class interface explicitly with a
GUID. Then all the early binding
clients can use the defined interface
and not worry about it changing on
them during development. That is why
the recommended option is None to tell
the CLR not to auto-generate it for
you. You can still implement the dual
interface though if you need it.