Ok, I'm on the verge of overthinking this. Is there a way to combine interfaces and attributes such that an attributed property in the implementing class fulfills the interface contract?
In my app I'd like to show a list of activities, which is an aggregation of events in the system such as a new message, a new task being created/assigned/updated, etc. It's just a quick hand list of what's been going on.
I thought about using an IIsActivity interface to flag entities that need to be a part of this aggregation. I really only need to show an activity title, the date it occurred, and link to the relevant area in the application. I don't want to enforce additi开发者_JAVA百科onal properties in the inheriting classes that simply end up duplicating information though. For example, a Task has an AssignedOn (DateTime), and a Message has a CreatedOn (DateTime). Both of this would fulfill the date requirement to be considered an Activity. What I don't want is a separate property just for the activity date. Same thing can go for the title (Message has a Title property, Task has a Name property).
So, I basically want to be able to say, "Get me anything this is an IIsActivity. Within each of those implementors, I expect there to be a property marked with an ActivityTitle attribute, and one with an ActivityDate attribute."
Too much?
I think your best approach is to use explicit interface implementation.
public interface IActivity
{
DateTime OccurredOn { get; }
}
public class Task : IActivity
{
public DateTime AssignedOn
{
get { /* implemenation */ }
}
DateTime IActivity.OccurredOn
{
get { return AssignedOn; }
}
}
public class Message : IActivity
{
public DateTime CreatedOn
{
get { /* implemenation */ }
}
DateTime IActivity.OccurredOn
{
get { return CreatedOn; }
}
}
And then you could use your classes like so:
public static void Main()
{
Task task = new Task();
Console.WriteLine(task.AssignedOn); // OK
Console.WriteLine(task.OccurredOn); // Compile Error
IActivity activity = task as IActivity;
if (activity != null)
{
Console.WriteLine(activity.AssignedOn); // Compile Error
Console.WriteLine(activity.OccurredOn); // OK
}
}
This is not exactly your design but I have used attributes to enforce some of the properties of my classes have a desired value. I'm consuming a webservice and I have to send some information , some of the fields require value, others dont...
[Serializable]
[AttributeUsage(AttributeTargets.Property)]
public class RequiredAttribute : Attribute
{
private CheckType[] _requiredtype;
public RequiredAttribute(params CheckType[] type)
{
_requiredtype = type;
}
public CheckType[] Requires
{
get { return _requiredtype; }
}
public static bool CheckRequirements(object applyto, out string errormessages)
{ ... }
private static bool RequiredSucceeded(object applyto, StringBuilder resultmessage)
{ ... }
}
[Serializable]
public enum CheckType
{
HasValue, // Checks that the property value is not null
CheckMinRequirements, // Will enforce the validation of properties on defined types
IsNotNullorEmpty, // For strings
HasElements, // Elements exist on arrays
ElementsRequirements // for collections
}
Now there is an example of a class using the attribute
[Serializable]
public class PurchaseInsurance
{
[Required(CheckType.IsNotNullorEmpty)]
public string PartnerBookingID
{
get;
set;
}
[Required(CheckType.IsNotNullorEmpty)]
public string Currency
{
get;
set;
}
public string ReferringURL;
[Required(CheckType.HasValue, CheckType.CheckMinRequirements)]
public PurchaserInfo Purchaser
{
get;
set;
}
[Required(CheckType.HasValue, CheckType.ElementsRequirements)]
public InsuranceProduct[] Products
{
get;
set;
}
...
}
Before sending the data to the webService I will check if each property complies with their attributes tags.
Althouth the CLR supports it, C# doesn't support interface implementation aliasing. You could achieve it in VB.NET though:
Public Interface IActivity ' this can even be in C# '
ReadOnly Property OccurredOn() As DateTime
End Interface
Public Class Task
Implements IActivity
Public ReadOnly Property AssignedOn() As DateTime Implements IActivity.OccurredOn
Get
' implementation... '
End Get
End Property
End Class
Public Class Message
Implements IActivity
Public ReadOnly Property CreatedOn() As DateTime Implements IActivity.OccurredOn
Get
' implementation... '
End Get
End Property
End Class
So, as mentioned by Brian Gideon, explicit interface implementation is what comes closer to your goal in C#.
精彩评论