Reputation: 105069
I have a generic interface that defines functionality to secure particular value types. Particular provider implementations are able to protect some value type values (i.e. ISecurityProvider<int>
) or strings (ISecurityProvider<string>
). That's why I put a generic type constraint to IConvertible
to cover both.
Provider interface definition
public interface ISecurityProvider<TSecurable>
where TSecurable : IConvertible // to constrain to struct types AND string
{
TSecurable Secure(TSecurable value);
}
Then I have my entity classes that should be able to use these providers and secure their own properties based on security provider's implementation.
I define an abstract base entity class that actual ones inherit from
public abstract class BaseEntity
{
protected bool IsSecured { get; set; }
protected virtual void SecureSelf<TSecurable>(ISecurityProvider<TSecurable> provider)
where TSecurable : IConvertible
{
if (!this.IsSecured)
{
this.IsSecured = true;
}
}
}
Example entity with identity property that has to be secured.
public class SomeDataRecord : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
public override void SecureSelf<TSecurable>(ISecurityProvider<TSecurable> provider)
{
if (!this.IsSecured)
{
base.SecureSelf(provider);
this.Id = provider.Secure(this.Id); // COMPILER ERROR
}
}
}
The error I'm getting is:
The best overloaded method match for 'ISecurityProvider.Secure(TSecurable)' has some invalid arguments.
How should I call provider.Secure()
method to make it work?
Basically I would like my individual entity classes to secure all applicable properties which may be of different types. As in my example where I have an integer and a string property.
My SecureSelf
method should secure all of them at the same time as they're all relying on the same IsSecured
property. So my example is not really the best one. I should likely rather provide a security provider factory to my SecureSelf
method and internally it should get particular provider instances to secure indiviual types of properties. Or so I think...
Upvotes: 0
Views: 2438
Reputation: 15161
You are getting that exception because "int" is not "TSecurable", you can avoid this making BaseEntity generic and in your specific class inherit from the base with a concrete type:
public interface ISecurityProvider<TSecurable>
where TSecurable : IConvertible // to constrain to struct types AND string
{
TSecurable Secure(TSecurable value);
}
public abstract class BaseEntity<TSecurable> where TSecurable : IConvertible
{
protected bool IsSecured { get; set; }
protected virtual void SecureSelf(ISecurityProvider<TSecurable> provider)
{
if (!this.IsSecured)
{
this.IsSecured = true;
}
}
}
public class SomeDataRecord : BaseEntity<int>
{
public int Id { get; set; }
public string Name { get; set; }
protected override void SecureSelf(ISecurityProvider<int> provider)
{
if (!this.IsSecured)
{
base.SecureSelf(provider);
this.Id = provider.Secure(this.Id); // COMPILER ERROR
}
}
}
Also, if everything will be IConvertible you can use a non-generic approach:
public interface ISecurityProvider
{
IConvertible Secure(IConvertible value);
}
public abstract class BaseEntity
{
protected bool IsSecured { get; set; }
protected virtual void SecureSelf(ISecurityProvider provider)
{
if (!this.IsSecured)
{
this.IsSecured = true;
}
}
}
public class SomeDataRecord : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
protected override void SecureSelf(ISecurityProvider provider)
{
if (!this.IsSecured)
{
base.SecureSelf(provider);
this.Id = (int)provider.Secure(this.Id);
this.Name = (string)provider.Secure(this.Name);
}
}
}
Upvotes: 0
Reputation: 144206
Given the way you're trying to use Secure
you should put the constraint on the method instead of on the interface:
public interface ISecurityProvider
{
TSecurable Secure<TSecurable>(TSecurable value) where TSecurable : IConvertible;
}
public abstract class BaseEntity
{
protected bool IsSecured { get; set; }
protected virtual void SecureSelf(ISecurityProvider provider)
{
if (!this.IsSecured)
{
this.IsSecured = true;
}
}
}
public class SomeDataRecord : BaseEntity
{
public int Id { get; set; }
public string Name { get; set; }
protected override void SecureSelf(ISecurityProvider provider)
{
if (!this.IsSecured)
{
base.SecureSelf(provider);
this.Id = provider.Secure(this.Id);
}
}
}
Upvotes: 2