How to annotate interface property get and set with attributes in F# - f#

How to translate the following COM interface to F#? I cannot figure out how to annotate get and set of a property.
Plus, for COM interop, do I need to annotate both a property itself and its get with DispId?
[ComImport, TypeLibType((short)0x1040), Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B")]
private interface IWshShortcut
{
[DispId(0)]
string FullName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0)] get; }
[DispId(0x3e8)]
string Arguments { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3e8)] set; }
[DispId(0x3ec)]
string RelativePath { [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ec)] set; }
[DispId(0x3ee)]
int WindowStyle { [DispId(0x3ee)] get; [param: In] [DispId(0x3ee)] set; }
[DispId(0x3ef)]
string WorkingDirectory { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] get; [param: In, MarshalAs(UnmanagedType.BStr)] [DispId(0x3ef)] set; }
[TypeLibFunc((short)0x40), DispId(0x7d0)]
void Load([In, MarshalAs(UnmanagedType.BStr)] string PathLink);
[DispId(0x7d1)]
void Save();
}

Here's a correct, though not literal, translation:
[<ComImport; Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B"); TypeLibType(0x1040s)>]
type private IWshShortcut =
[<DispId(0)>]
abstract member FullName : [<MarshalAs(UnmanagedType.BStr)>] string with get
[<DispId(0x3e8)>]
abstract member Arguments : [<MarshalAs(UnmanagedType.BStr)>] string with get, set
[<DispId(0x3ec)>]
abstract member RelativePath : [<MarshalAs(UnmanagedType.BStr)>] string with set
[<DispId(0x3ee)>]
abstract member WindowStyle : int with get, set
[<DispId(0x3ef)>]
abstract member WorkingDirectory : [<MarshalAs(UnmanagedType.BStr)>] string with get, set
[<DispId(0x7d0); TypeLibFunc(0x40s)>]
abstract member Load : [<MarshalAs(UnmanagedType.BStr)>] PathLink:string -> unit
[<DispId(0x7d1)>]
abstract member Save : unit -> unit
As you found, you cannot add attributes to an abstract property's underlying getter/setter methods in F#, only to the property itself, but it doesn't matter for this particular interface:
String properties with both get and set need the same MarshalAs for both anyway.
In is the default directionality for string parameters, so specifying it would be redundant anyway.
Applying DispId to the property getter as your C# code does is legal but pointless – while DispId can be applied to both methods and properties, and property getters and setters technically happen to be methods, the attribute only has an effect for the property itself.
N.b. because the CLR marshals string parameters for COM methods as BStrs by default, we can omit all the MarshalAs directives as well and make this look a bit more trim (albeit less explicit):
[<ComImport; Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B"); TypeLibType(0x1040s)>]
type private IWshShortcut =
[<DispId(0)>] abstract member FullName:string with get
[<DispId(0x3e8)>] abstract member Arguments:string with get, set
[<DispId(0x3ec)>] abstract member RelativePath:string with set
[<DispId(0x3ee)>] abstract member WindowStyle:int with get, set
[<DispId(0x3ef)>] abstract member WorkingDirectory:string with get, set
[<DispId(0x7d0); TypeLibFunc(0x40s)>] abstract member Load : PathLink:string -> unit
[<DispId(0x7d1)>] abstract member Save : unit -> unit
Of course, all of this applies to the C# implementation as well, so it can be similarly simplified:
[ComImport, Guid("F935DC23-1CF0-11D0-ADB9-00C04FD58A0B"), TypeLibType((short)0x1040)]
private interface IWshShortcut
{
[DispId(0)] string FullName { get; }
[DispId(0x3e8)] string Arguments { get; set; }
[DispId(0x3ec)] string RelativePath { set; }
[DispId(0x3ee)] int WindowStyle { get; set; }
[DispId(0x3ef)] string WorkingDirectory { get; set; }
[DispId(0x7d0), TypeLibFunc((short)0x40)] void Load(string PathLink);
[DispId(0x7d1)] void Save();
}

Related

Implement generic interface: construct causes code to be less generic than indicated by the type annotations

I need to implement an interface like this:
interface IEvent<T> : IEvent {
T Data { get; }
}
public interface IEvent
{
Guid Id { get; set; }
long Version { get; set; }
long Sequence { get; set; }
object Data { get; }
Guid StreamId { get; set; }
string StreamKey { get; set; }
DateTimeOffset Timestamp { get; set; }
string TenantId { get; set; }
Type EventType { get; }
string EventTypeName { get; set; }
string DotNetTypeName { get; set; }
}
That's what I came up with:
type WrappedEvent<'T>(x: 'T) =
interface Events.IEvent with
member val Data = x with get
member val DotNetTypeName = null with get, set
member val EventType = null
member val EventTypeName = null with get, set
member val Id = Guid.Empty with get, set
member val Sequence = int64 (0) with get, set
member val StreamId = Guid.Empty with get, set
member val StreamKey = null with get, set
member val TenantId = null with get, set
member val Timestamp = DateTimeOffset.MinValue with get, set
member val Version = int64 (0) with get, set
WrappedEvent is used like this:
let MapToSubtype subtype =
match subtype with
| CustomerRegistered registeredCustomer -> WrappedEvent<CustomerRegisteredEvent> registeredCustomer :> Events.IEvent
| CustomerDeleted deletedCustomer -> WrappedEvent<CustomerDeletedEvent> deletedCustomer :> Events.IEvent
The compiler throws an error for <'T> at WrappedEvent<'T>
This type parameter has been used in a way that constrains it to always be 'obj'
This code is less generic than required by its annotations because the explicit type variable 'T' could not be generalized.
It was constrained to be 'obj'.
A warning is shown for Data at member val Data:
This construct causes code to be less generic than indicated by the type annotations.
The type variable 'T has been constrained to be type 'obj'.
How do I solve this?
Update:
If I'm implementing the interface like this interface Events.IEvent<'T> with (using the generic parameter), I get this error:
No implementation was given for 'Events.IEvent.get_Data() : obj'.
Note that all interface members must be implemented and listed under an appropriate 'interface' declaration, e.g. 'interface ... with member ...'.
First, you're implementing two interfaces here, not one, - IEvent<T> and its base interface IEvent. As such, you need to add two interface ... with blocks - one for each:
type WrappedEvent<'T>(x: 'T) =
interface Events.IEvent<'T> with
member val Data = x with get
interface Events.IEvent with
member val Data = x with get
member val DotNetTypeName = null with get, set
member val EventType = null
...
Second, when implementing the IEvent interface, note the type of its Data member: it's obj. So if you initialize that member with x, it follows that x must have type obj. And that's the source of your original error: x is used in such a way that will make it constrained to obj.
To fix this, you need to downcast x to obj before initializing Data with it:
interface Events.IEvent with
member val Data = x :> obj with get
But wait! This will still not work. The problem is, member val declares not just a property, but also a backing field for it. And now you're declaring two different backing fields, both named Data, but of different types. (also, btw, you don't actually need separate backing fields, right? because you already have x)
So to get around that, make them properties without backing fields:
interface Events.IEvent<'T> with
member self.Data with get() = x
interface Events.IEvent with
member self.Data with get() = x :> obj
...

struct system.Int32 does not have type parameters

I kept receiving the error message:
struct system.Int32 does not have type parameters
in my interface method below. Does anyone know what am doing wrong?
public class StatementRptParamId {
public Int32 ReportParameterId { get; set; }
}
public interface IStatementRptParamId {
Int32<StatementRptParamId> GetStatementRptParameter(string connectionString, string customerNumber);
}
Error happens on this line: Int32<StatementRptParamId>...
It looks like you're trying to use Int32 as a generic, which is incorrect. It looks like you think you're specifying the return type of your method call, which you also don't need to do. You've already given a type to the name. Just change your definition to:
StatementRptParamId GetStatementRptParameter(string connectionString,
string customerNumber);
You can then use the field on the class to get your value:
var val = GetStatementRptParameter(someConnectionString, someCustomerNumber);
var id = val.ReportParameterId;

creating a class for something trivial ?

A Enum is coming back from the service layer with 1 out of 4 options and am using a case statement to handle it in my web code. I thought that I will be doing this at several places and to have some design pattern in place. Now based on each value from Enum I am doing is returning a string . creating a class for each enum seems to be a overkill. what is the best way to handle this
You don't need to create a new subclass for each enum value, you can have multiple instances of the same class, one for each value:
public class MyEnumType {
private readonly string value;
private MyEnumType(string value) {
this.value = value;
}
public string Value {
get { return value; }
}
public static readonly MyEnumType ValueA = new MyEnumType("foo");
public static readonly MyEnumType ValueB = new MyEnumType("bar");
...
}

Implement IEquatable for POCO

I noticed that EF's DbSet.Add() is quite slow. A little googling turned up a SO answer that promises up to 180x performance gains:
https://stackoverflow.com/a/7052504/141172
However, I do not understand exactly how to implement IEquatable<T> as suggested in the answer.
According to MSDN, if I implement IEquatable<T>, I should also override Equals() and GetHashCode().
As with many POCO's, my objects are mutable. Before being committed to the database (SaveChanges()), new objects have an Id of 0. After the objects have been saved, the Id serves as an ideal basis for implementing IEquatable, Equals() and GetHashCode().
It is unwise to include any mutable property in a hash code, and since according to MSDN
If two objects compare as equal, the GetHashCode method for each
object must return the same value
Should I implement IEquatable<T> as a property-by-property comparison (e.g. this.FirstName == other.FirstName) and not override Equals() and GetHashCode()?
Given that my POCO's are used in an EntityFramework context, should any special attention be paid to the Id field?
I came across your question in search for a solution to the same question. Here is a solution that I am trying out, see if it meets your needs:
First, all my POCOs derive from this abstract class:
public abstract class BasePOCO <T> : IEquatable<T> where T : class
{
private readonly Guid _guid = Guid.NewGuid();
#region IEquatable<T> Members
public abstract bool Equals(T other);
#endregion
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != typeof (T))
{
return false;
}
return Equals((T)obj);
}
public override int GetHashCode()
{
return _guid.GetHashCode();
}
}
I created a readonly Guid field that I am using in the GetHashCode() override. This will ensure that were I to put the derived POCO into a Dictionary or something else that uses the hash, I would not orphan it if I called a .SaveChanges() in the interim and the ID field was updated by the base class This is the one part I'm not sure is completely correct, or if it is any better than just Base.GetHashCode()?. I abstracted the Equals(T other) method to ensure the implementing classes had to implement it in some meaningful way, most likely with the ID field. I put the Equals(object obj) override in this base class because it would probably be the same for all the derived classes too.
This would be an implementation of the abstract class:
public class Species : BasePOCO<Species>
{
public int ID { get; set; }
public string LegacyCode { get; set; }
public string Name { get; set; }
public override bool Equals(Species other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ID != 0 &&
ID == other.ID &&
LegacyCode == other.LegacyCode &&
Name == other.Name;
}
}
The ID property is set as the primary key in the Database and EF knows that. ID is 0 on a newly created objects, then gets set to a unique positive integer on .SaveChanges(). So in the overridden Equals(Species other) method, null objects are obviously not equal, same references obviously are, then we only need to check if the ID == 0. If it is, we will say that two objects of the same type that both have IDs of 0 are not equal. Otherwise, we will say they are equal if their properties are all the same.
I think this covers all the relevant situations, but please chime in if I am incorrect. Hope this helps.
=== Edit 1
I was thinking my GetHashCode() wasn't right, and I looked at this https://stackoverflow.com/a/371348/213169 answer regarding the subject. The implementation above would violate the constraint that objects returning Equals() == true must have the same hashcode.
Here is my second stab at it:
public abstract class BasePOCO <T> : IEquatable<T> where T : class
{
#region IEquatable<T> Members
public abstract bool Equals(T other);
#endregion
public abstract override bool Equals(object obj);
public abstract override int GetHashCode();
}
And the implementation:
public class Species : BasePOCO<Species>
{
public int ID { get; set; }
public string LegacyCode { get; set; }
public string Name { get; set; }
public override bool Equals(Species other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ID != 0 &&
ID == other.ID &&
LegacyCode == other.LegacyCode &&
Name == other.Name;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as Species);
}
public override int GetHashCode()
{
unchecked
{
return ((LegacyCode != null ? LegacyCode.GetHashCode() : 0) * 397) ^
(Name != null ? Name.GetHashCode() : 0);
}
}
public static bool operator ==(Species left, Species right)
{
return Equals(left, right);
}
public static bool operator !=(Species left, Species right)
{
return !Equals(left, right);
}
}
So I got rid of the Guid in the base class and moved GetHashCode to the implementation. I used Resharper's implementation of GetHashCode with all the properties except ID, since ID could change (don't want orphans). This will meet the constraint on equality in the linked answer above.
As with many POCO's, my objects are mutable
But tehy should NOT be mutable on the fields that are the primary key. Per defintiion, or you are in a world of pain database wise anyway later.
Generate the HashCode ONLY on the fields of the primay key.
Equals() must return true IFF the participating objects have the same hash code
BZZZ - Error.
Hashcodes are double. It is possible for 2 objects to have different values and the smae hashcode. A hsahsode is an int (32bit). A string can be 2gb long. You can not mapp every possible string to a separate hashcode.
IF two objects have the same hashcode, they may be diferent. If two objects are the same, they can NOT have different hashcodes.
Where do you get the idea that Equals must return true for objects with the same hashcode?
Also, PCO or not, an object mapped to a database and used in a relation MUST have a stable primary key (which can be used to run the hashcode calculation). An object not having this STIL lshould have primary key (per SQL Server requirements), using a sequence / artificial primary key works here. Again, use that to run the HashCode calculation.
First thing first: Sorry my lame English :)
As TomTom say, they shouldn't be mutable just because they still not received PK/Id...
In our EF:CF system, we use generated negative id (assigned in base class ctor or, if you use ProxyTracking, in ObjectMaterialized event) for every new POCO. Its pretty simple idea:
public static class IdKeeper
{
private static int m_Current = int.MinValue;
private static Next()
{
return ++m_Current;
}
}
MinValue and incremen should be important, because EF will sort POCOs by their PK before committing changes to db and when you use "-1, -2, -3", POCOs are saved flipped, which in some cases (not according to what sort) may not be ideal.
public abstract class IdBase
{
public virtual int Id { get; set; }
protected IdBase()
{
Id = IdKeeper.Next();
}
}
If POCO is materialized from DB, his Id will be override with actual PK as well as when you call SaveChanges(). And as bonus, every single "not yet saved" POCO id will be unique (that should come handy one day ;) )
Comparing two POCO with IEquatable (why does dbset work so slow) is then easy:
public class Person
: IdBase, IEquatable<Person>
{
public virtual string FirstName { get; set; }
public bool Equals(Person other)
{
return Id == other.Id;
}
}

Should the EnumDataTypeAttribute work correctly in .NET 4.0 using Entity Framework?

I have an enumeration which I'd like to persist as a value of some sort into the underlying database so that I can bring it back and forth.
I have read some articles that suggest to create a enumeration wrapper with static implicit operators defined, mapped using a ComplexType object mapping as described in the link below.
How to fake Enums in EF4
This solution works flawlessly! My thanks to Alex James.
Aside, I discovered of the EnumDataTypeAttribute Class which purpose seems to handle enums persistence through Entity Framework. I tried it and it doesn't seem to work at all. Here's a code sample.
public enum StreetDirection {
East
, None
, North
, NorthEast
, NorthWest
, South
, SouthEast
, SouthWest
, West
}
public enum StreetType {
Avenue
, Boulevard
, Court
, Crescent
, Drive
, Hill
, None
, Road
, Street
}
public class StreetTypeWrapper {
public int Value {
get {
return (int)t;
}
set {
t = (StreetType)value;
}
}
public StreetType EnumValue {
get {
return t;
}
set {
t = value;
}
}
public static implicit operator int(StreetTypeWrapper w) {
return w.Value;
}
public static implicit operator StreetType(StreetTypeWrapper w) {
return w == null ? StreetType.None : w.EnumValue;
}
public static implicit operator StreetTypeWrapper(int i) {
return new StreetTypeWrapper() { Value = i };
}
public static implicit operator StreetTypeWrapper(StreetType t) {
return new StreetTypeWrapper() { EnumValue = t };
}
private StreetType t;
}
public class Street {
[EnumDataType(typeof(StreetDirection))]
public StreetDirection Direction { get; set; }
public string Name { get; set; }
public int StreetId { get; set; }
public StreetTypeWrapper Type { get; set; }
}
public class StreetTypeMapping
: ComplexTypeConfiguration<StreetTypeWrapper> {
public StreetTypeMapping() {
Property(o => o.Value)
.HasColumnName("StreetType");
}
}
Now, if I believe and/or understanding correctly what MSDN says about the EnumDataTypeAttribute class, the Direction property should get persisted into the database. Well, it doesn't! I can't find a reason for this, except that EF doesn't support enums persistence. As for the StreetTypeWrapper and its StreetTypeMapping class, it does work flawlessly.
Are there any clue why the EnumDataType shouldn't work as expected?
This is because of design flaw in .NET framework. .NET framework contains famous System.ComponentModel.DataAnnotations namespace where multiple different attributes are defined. Many different parts of .NET framework are using this namespace but they are using it to achieve different tasks and every such part use only some subset of attributes. This causes a lot of confusion.
EnumDataTypeAttribute is such example. This attribute is only for ASP.NET Dynamic Data. It allows you to mark int property with this attribute and automatically generated UI will show drop down with enum values instead of textbox for numeric values. So there is mapping from enum to int but it is in UI layer not in model / persistence layer.

Resources