Reputation: 21126
I have the following interface:
public interface ISoftDeletable
{
bool IsDeleted { get; set; }
}
And my entity:
public class Field : ISoftDeletable
{
[Key]
public int FieldID { get; set; }
public bool IsDeleted { get; set; }
...
In my generic repository i have:
...
if( entity is ISoftDeletable )
{
entity.IsDeleted = true; // does not know entity is implementing ISoftDeletable, so is throwing error that i cannot set IsDeleted
}
...
but of course, c# does not know entity is implementing ISoftDeletable as entity is generic type.
How can i make C# know the IsDeleted property is okay to set?
Upvotes: 1
Views: 159
Reputation: 13148
You can use as
:
var maybeSoftDeletable = entity as ISoftDeletable;
if (maybeSoftDeletable != null)
maybeSoftDeletable.IsDeleted = true;
maybeSoftDeletable
will be null
if entity
is not an ISoftDeletable
, or otherwise will be an ISoftDeletable
reference to the same object.
As per George's answer, you can also cast:
var definitelyASoftDeletable = (ISoftDeletable)entity;
definitelyASoftDeletable.IsDeleted = true;
The main difference is whether you know entity
is of the type or not. If entity
is allowed to be one or not, then use as
. If entity
is supposed to be one, then use a cast, which will cause an exception if it violates that rule.
UPDATE: lately I've been using some Maybe
and MaybeAs
extension methods, which I'm loving so far:
public static void MaybeAs<T>(
this object pObject,
Action<T> pAction
) {
var maybeT = pObject as T;
if (maybeT == null)
return;
var t = maybeT;
pAction(t);
}
// and one for functions
public static TResult MaybeAs<TObject, TResult>(
this object pObject,
Func<TObject, TResult> pFunc
) where TObject : class
where TResult: class {
var maybeT = pObject as TObject;
if (maybeT == null)
return null;
var t = maybeT;
return pFunc(t);
}
// to allow for primitive return values
public static TResult MaybeAs<TObject, TResult>(
this object pObject,
Func<TObject, TResult> pFunc,
TResult pValueWhenNot
) where TObject : class {
var maybeT = pObject as TObject;
if (maybeT == null)
return pValueWhenNot;
var t = maybeT;
return pFunc(t);
}
Used like:
entity.MaybeAs<ISoftDeletable>(softDeletable => softDeletable.IsDeleted = true);
Upvotes: 3
Reputation: 14329
To my knowledge, the C# type system does not understand that in if (x is X) { (1) }
that x
has type X
or has a subtype of X
in (1)
. This may not even be a safe assumption in C#, I do not know (concurrency?).
Instead, you might write this.
if (entity is ISoftDeletable) {
((ISoftDeletable)entity).IsDeleted = true;
}
This has the unfortunate consequence of casting entity
twice, once for the branch condition and again to set IsDeleted
. The cost of casting can be non-trivial (I'll let you decide for your case). Here is another variation that does not do this.
var deletableEntity = entity as ISoftDeletable;
if (deletableEntity != null) {
deletableEntity.IsDeleted = true;
}
Upvotes: 4
Reputation: 54618
Based on your code I'd slightly change it to:
var softDelete = entity as ISoftDeletable;
if(softDelete != null)
{
softDelete .IsDeleted = true;
}
This code is a little more readable about what it is actually doing (IMO).
Upvotes: 6
Reputation: 57872
I don't know anything more about your setup than what you've provided; but this feels fishy to me. It may not be, but I don't have enough of a picture to know.
To solve your immediate issue, you could cast the entity
to the ISoftDeletable
so that the ISDeleted
property can be set:
((ISoftDeletable)entity).IsDeleted = true;
Again; something feels off about having to do that; but it's 9:47pm, so I'm not going to spend too much brain power to figure that out tonight.
Upvotes: 5