Generic Objects C# - c#

So I have been working with the Neo4jClient library for C# and I am fairly new to both worlds.
I have this POCO here:
public class SetEntity
{
public string GUID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string CreatedDate { get; set; }
}
This object class is used in various methods, one in particular for creating a relationship between two nodes however I have to explicitly say which POCO is used to create it IRelationshipAllowingSourceNode<SetEntity> and IRelationshipAllowingTargetNode<EntityInstance>. Below is the entire class that handles that.
class GraphRelationshipEntityInstanceToSetEntity : Relationship, IRelationshipAllowingSourceNode<EntityInstance>, IRelationshipAllowingTargetNode<SetEntity>
{
string RelationshipName;
public GraphRelationshipEntityInstanceToSetEntity(NodeReference targetNode)
: base(targetNode)
{
}
public GraphRelationshipEntityInstanceToSetEntity(string RelationshipName, NodeReference targetNode)
: base(targetNode)
{
this.RelationshipName = RelationshipName;
}
public override string RelationshipTypeKey
{
get { return RelationshipName; }
}
}
Is there a way that I can pass <SetEntity> or any other objects into IRelationshipAllowingSourceNode<Object>. I see it as unnecessary to create this class for every node type that will have a relationship with another node type.

I'm not familiar with the Neo4jclient but can comment on generics in c#.
In c# you can define an interface with which is said to have an open generic type. That is, the neo4jclient presumably declares an interface IRelationshipAllowingSourceNode<T> with some method on which presumably use an instance of T/returns T.
This is said to be an interface with an open generic type.
When you implement that interface you have close the open generic type by specifying the exact type you're working with. You can however, make your class use two open generic types as follows, and then close the generic types when you instantiate GraphRelationshipEntityInstanceToSetEntity. See below.
class GraphRelationshipEntityInstanceToSetEntity<T, T1> : Relationship, IRelationshipAllowingSourceNode<T>, IRelationshipAllowingTargetNode<T1>
{
string RelationshipName;
public GraphRelationshipEntityInstanceToSetEntity(NodeReference targetNode)
: base(targetNode)
{
}
public GraphRelationshipEntityInstanceToSetEntity(string RelationshipName, NodeReference targetNode)
: base(targetNode)
{
this.RelationshipName = RelationshipName;
}
public override string RelationshipTypeKey
{
get { return RelationshipName; }
}
}
See here for another question which has been answered on generics:
Generics -Open and closed constructed Types
Hope that this helps.
Tim

Related

Generic Interface type conversion issues

I have been battling with this bit of code for a while now and I am trying to get a solution as it is literally the last part before it goes to testing.
I have the following interfaces and classes (simplified to the relevant parts):
public interface ITagParent<T> where T : ITag
{
List<TagAddOn<T>> TagCollection { get; set; }
}
public interface ITag
{
int Id { get; set; }
string Description { get; set; }
TagGroup TagGroup { get; set; }
}
public class TagAddOn<T> : ViewModelBase where T : ITag
{
private T _currentTag;
public T CurrentTag
{
get { return _currentTag; }
set { _currentTag = value; }
}
}
public partial class Customer : ITagParent<CustomerTag>
{
List<TagAddOn<CustomerTag>> _tagCollection;
public List<TagAddOn<CustomerTag>> TagCollection
{
get { return _tagCollection; }
set { _tagCollection = value; }
}
}
public partial class CustomerTag : ITag
{
public int Id { get; set; }
}
public class TagAddOnManager
{
public static string GetTagCurrentValue(List<TagAddOn<ITag>> dataObjectAddOns)
{
// LOTS OF SNIPPING!
return string.Empty;
}
}
I am trying to use the GetTagCurrentValue method in the TagAddOnManager class like this:
string value = TagAddOnManager.GetTagCurrentValue(
((ITagParent<ITag>)gridCell.Row.Data).TagCollection));
Everything compiles fine, but errors when trying to cast gridCell.Row.Data to ITagParent<ITag>. I understand this is due to covarience and a workaround (if not a terribly safe one) is to mark T in the ITagParent interface with the out keyword, but that won't work as you can see it is used in the TagCollection property, which can't be read only.
I tried casting the above to ITagParent<CustomerTag>, but this fails at compile time with a 'cannot convert' error when trying to feed it into my GetTagCurrentValue method.
Another option I considered is using some base classes instead of the ITagParent interface, but that won't work as the Customer object already inherits from another base class, which can't be modified for this implementation.
I know I could just overload the GetTagCurrentValue method with List<TagAddOn<CustomerTag>> as the parameter type and all other variations, but that really seems like a 'I give up' solution. I could probably use reflection to get the desired results, but that would be unwieldy and not very efficient, especially considering this method could be called a lot in a particular process.
So does anyone have any suggestions?
Could you use something like that
public class TagAddOnManager
{
public static string GetTagCurrentValue<TTag>(ITagParent<TTag> tagParent)
where TTag : ITag
{
// Just an example.
return tagParent.TagCollection.First().CurrentTag.Description;
}
}
and use it like that?`
var value = TagAddOnManager.GetTagCurrentValue((Customer)CustomergridCell.Row.Data);

How to make type safe method in class shared via MEF?

I have class which I want to export via MEF. In this example it's string type Displayer but in program will be many special type Displayers. I will do ImportMany<*IDisplayer> to get a list of available Displayers, and I will choose the Displayer from that list, for a given object to show.
My question how would be possible to make Display method type save? Or cast in it type safe? And still have Displayer usable via MEF.
P.S.
Using MEF I can't make interface like IDisplayer<*T>, because I will be not able to get a ImportMany<*IDisplayer<*T>> or something.
[DisplayableTypes(typeof(String))]
public class StringObjectDisplayer : IDisplayer
{
public void Display(object objectToDisplay)
{
var displayableObject = (string)objectToDisplay;
}
private Type GetAttributeParamenters()
{
return GetType().GetCustomAttributes(typeof(DisplayableTypesAttribute), true).OfType<DisplayableTypesAttribute>().First().SupportedType;
}
}
public class DisplayableTypesAttribute : ExportAttribute, IExportableElement
{
public DisplayableTypesAttribute(Type supportedType)
: base(typeof(IDisplayer))
{
SupportedType = supportedType;
}
public Type SupportedType { get; private set; }
}
public interface IDisplayer
{
void Display(object objectToDisplay);
}
public interface IExportableElement
{
Type SupportedType { get; }
}

Can C# constraints be used without a base type?

I have some classes with common properties, however, I cannot make them derive from a base type (LINQ-to-SQL limitations).
I would like to treat them as if they had a base type, but not by using Reflection (performance is critical).
For example:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
}
public class Vehicle
{
public int Id { get; set; }
public string Label { get; set; }
}
In this case I would be happy if I had the Id property available, regardless of the type I'm holding.
Is there any way in C# to to something similar to this:
public static int GetId<T>(T entity) where T // has an int property 'Id'
{
return entity.Id;
}
I guess I could have used dynamic, however, I'm looking for a way to restrict the code in compile time from using this method for an object that has no Id property.
You can use interfaces:
public interface IHasId
{
int Id { get; }
}
public class User : IHasId { ... }
public class Vehicle : IHasId { ... }
public static int GetId<T>(T entity) where T : IHasId
{
return entity.Id;
}
However, if you are not able to modify the classes to add the interface, you won't be able to do this. No compile-time checks will verify that a property exists on T. You'd have to use reflection - which is slow and obviously not ideal.
There is no way to guarantee a type has a given member without constraining to a common base type or interface. One way to work around this limitation is to use a lambda to access the value
public static int Use<T>(T value, Func<T, int> getIdFunc) {
int id = getIdFunc(value);
...
}
Use(new User(), u => u.Id);
Use(new Vehicle(), v => v.Id);
You can create an interface with the common properties and make your classes implement it:
public interface IEntity
{
int Id { get; set; }
}
public class User : IEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
}
public class Vehicle : IEntity
{
public int Id { get; set; }
public string Label { get; set; }
}
public static int GetId<T>(T entity) where T : IEntity
{
return entity.Id;
}
You could simplify GetId like this:
public static int GetId(IEntity entity)
{
return entity.Id;
}
The other answers mentioning the interface approach are certainly good, but I want to tailor the response to your situation involving Linq-to-SQL.
But first, to address the question title as asked
Can C# constraints be used without a base type?
Generally, the answer is no. Specifically, you can use struct, class, or new() as constraints, and those are not technically base types, and they do give some guidance on how the type can be used. That doesn't quite rise to the level of what you wish to do, which is to limit a method to types that have a certain property. For that, you will need to constrain to a specific interface or base class.
For your specific use case, you mention Linq-to-SQL. If you are working from models that are generated for you, then you should have options to modify those classes without modifying the generated model class files directly.
You probably have something like
// code generated by tool
// Customer.cs
public partial class Customer // : EntityBaseClasses, interfaces, etc
{
public int ID
{
get { /* implementation */ }
set { /* implementation */ }
}
}
And other similar files for things such as Accounts or Orders or things of that nature. If you are writing code that wishes to take advantage of the commonly available ID property, you can take utilize the partial in the partial class to define a second class file to introduce a common interface type to these models.
public interface IIdentifiableEntity
{
int ID { get; }
}
And the beauty here is that using it is easy, because the implementation already exists in your generated models. You just have to declare it, and you can declare it in another file.
public partial class Customer : IIdentifiableEntity { }
public partial class Account : IIdentifiableEntity { }
// etc.
This approach has proven valuable for me when using a repository pattern, and wishing to define a general GetById method without having to repeat the same boilerplate in repository after repository. I can constrain the method/class to the interface, and get GetById for "free."
Either you need to make both classes implement an interface with the properties you need, and use that in the generic constraint, or you write separate methods for each type. That's the only way you'll get compile-time safety.

C# upcast generic type to interface

This is similar to another topic I recently posted, but perhaps this might be simpler and clearer:
I want to accomplish the following (or something very similar)...
IManageableEntryDao<IManageableEntry> dao = new CompanyNameDao();
... with the following classes:
public interface IManageableEntry {
string Name { get; set; }
}
public class CompanyName : IManageableEntry {
public string Name { get; set; }
}
public interface IManageableEntryDao<T> where T : IManageableEntry {
}
public class CompanyNameDao : IManageableEntryDao<CompanyName> {
}
If I try to do a cast as IManageableEntryDao<IManageableEntry>, I get a null.
I believe you need covariance for this to work. This feature is only available in C# 4.0. What you need to do:
public interface IManageableEntryDao<out T> where T : IManageableEntry { }
See Variance in Generic Interfaces. Change the interface to IManageableEntryDao<out T> and it should work (unless the interface uses it in a way which makes this invalid).

How to have a list of ProblemBase<TResult>? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do I create a list of objects that inherit from the same generic class with varying types?
I'm using several objects where they are inherited from an abstract class. But to use the abstract class must be declara a generic datatype.
I'm having problems because I need to have a list where contains a list of ProblemBase, although each one contains a different TResult datatype.
public abstract class ProblemBase<TResult>
{
TResult[] Array;
}
And I want to get Array property. That's the problem.
This type of thing happens for me quite often. The solution I typically go with is to have a base class for ProblemBase<T> that is type free:
public abstract class ProblemBase
{
public abstract object Result { get; }
}
public abstract class ProblemBase<TResult> : ProblemBase
{
public override object Result
{
get { return Result; }
}
new public TResult Result { get; private set; }
}
Whenever you need a collection of problems, then, you can make a collection of ProblemBase without the generics.
If TResult has its own required inheritance hierarchy, then you can do this instead:
public abstract class ProblemBase
{
public abstract ResultBase Result { get; }
}
public abstract class ProblemBase<TResult> : ProblemBase
where TResult : ResultBase
{
public override ResultBase Result { get { return Result; } }
new public TResult Result { get; private set; }
}

Categories

Resources