Is it possible to create generic restriction in C# using where to select only classes, who have Field with some name.
for example, I have AbstractService<T>
and I have a method IEnumerable<T> ProvideData(userId);
inside provide data I should select only instances with the same user bla-bla-bla.Where(d => d.UserId == userId). But d.UserId could not be resolved. How it possible to resolve this?
IMPORTANT: I can't inherit T from class or interface, which have UserID field.
An interface is what your are looking for:
public interface IWithSomeField
{
int UserId { get; set; }
}
public class SomeGenericClasss<T>
: where T : IWithSomeField
{
}
public class ClassA : IWithSomeField // Can be used in SomeGenericClass
{
int UserId { get; set; }
}
public class ClassB // Can't be used in SomeGenericClass
{
}
[Edit] As you edited your question to state you cannot change class to implement an interface, here is some alternatives, but none relies on generic constraint :
Check the type in the constructor :
code :
public class SomeClass<T>{
public SomeClass<T>()
{
var tType = typeof(T);
if(tType.GetProperty("UserId") == null) throw new InvalidOperationException();
}
}
Use code contract invariant (not sure about the syntax) :
code :
public class SomeClass<T>{
[ContractInvariantMethod]
private void THaveUserID()
{
Contract.Invariant(typeof(T).GetProperty("UserId") != null);
}
}
Extend existing classes with partial classes
If your source classes are generated, you can cheat. I used this technique with lots of Web References having the same kind of parameter objects
Imagine the Web references produced this proxy code :
namespace WebServiceA {
public class ClassA {
public int UserId { get; set; }
}
}
namespace WebServiceB {
public partial class ClassB {
public int UserId { get; set; }
}
}
You can wrap them using in your own code:
public interface IWithUserId
{
public int UserId { get; set; }
}
public partial class ClassA : IWithUserId
{
}
public partial class ClassB : IWithUserId
{
}
then, for your service, you can instantiate AbstractService for any of the Class of the several web services :
public class AbstractService<T> where T : IWithUserId
{
}
This technique works great but only applies when you can extend class in the same project because of the partial keyword trick.
Related
namespace Test
{
public class A
{
public string Name { get; set; }
}
public class AValidator : AbstractValidator<A>
{
public AValidator()
{
RuleFor(t => t.Name)
.NotEmpty()
.MinimumLength(10)
.MaximumLength(20);
}
}
public class B
{
public string Name { get; set; }
}
public class BValidator : AbstractValidator<B>
{
public BValidator()
{
RuleFor(t => t.Name)
.NotEmpty()
.MinimumLength(10)
.MaximumLength(20);
}
}
}
tried to create a common like this:
namespace Test2
{
public interface IPerson
{
public string Name { get; set; }
}
public abstract class CommonABValidators<T> :
AbstractValidator<T> where T : IPerson
{
protected CommonABValidators()
{
RuleFor(x => x.Name).NotNull();
}
}
}
but by calling
public class AValidator : CommonABValidators<A>
It should be convertible to IPerson, but in my case I have diffeent props in A that are not convertible to IPerson
Any Idea how to extract common params into common Validator?
What you've done looks correct. Just make sure that your class A implements the IPerson interface and the validator will start working.
Another option that you can try at least is to Include rules. Here you can find the official documentation: https://docs.fluentvalidation.net/en/latest/including-rules.html
All you need is to call Include(new CommonValidator()); and the common rules will be automatically included without inheriting a common base type.
I am trying to do the following in C#.
public class Parent<T> where T : Parent<???>
{
public T Prop { get; set; }
}
public class Child : Parent<Child>
{
}
How can I do it?
This works fine:
public class Parent<T> where T : Parent<T>
{
public T Prop { get; set; }
}
public class Child : Parent<Child>
{
}
Do be careful with this as c# does not enforce a true Parent/Child relationship. For example, given the above code, it is also legal for me to then do this:
public class Stranger : Parent<Child>
{
}
If you write unit tests then it's worth writing a type checker that looks for this mispattern.
Is there any nice, elegant way to get properties from generic type used in abstract superclass without using interfaces?
Here's an example:
public abstract class CoolBase<T>
where T : class
{
private IEnumerable<T> somEnumerable;
public void GetPersonProperties()
{
var name = somEnumerable.First().Name; //this doesn't work
}
}
public class CoolA : CoolBase<Person>
{
}
public class Person
{
public string Name { get; set; }
public string Region { get; set; }
}
}
The goal of using generic classes is type-flexibility -
therefore it makes no sence to declare a method in a generic class which
uses Person-specific methods.
You should implement such detailed methods in the concrete implementations of
your abstract, generic class (here CoolA).
Maybe it is helpful for you to declare an abstract method getProperties()
int the generic, abstract class, wich can be implemented in CoolA via using
Person-specific code.
public abstract class CoolBase<T>
where T : class
{
private IEnumerable<T> somEnumerable;
public abstract void getProperties();
}
public class CoolA : CoolBase<Person>
{
public override void getProperties()
{
//should work, somEnumberable is made of Persons here
var name = somEnumerable.First().Name;
}
}
It makes no sense to put GetPersonProperties in CoolBase. CoolBase is generic, so should not have a class-specific functionality within it.
You could create a abstract method in CoolBase and implement it in your derived type:
public abstract class CoolBase<T> where T : class
{
protected IEnumerable<T> somEnumerable;
public abstract void GetProperties();
}
public class CoolA : CoolBase<Person>
{
public override void GetProperties()
{
var name = somEnumerable.First().Name;
}
}
public class Person
{
public string Name { get; set; }
public string Region { get; set; }
}
Alternatively, you could you reflection to get at the properties of T at runtime:
public abstract class CoolBase<T> where T : class
{
private IEnumerable<T> somEnumerable;
public void GetProperties()
{
foreach (var prop in typeof (T).GetProperties())
{
// do something with each property
}
}
}
I have the following:
public interface IEntity
{
IEntityContent Data { get; set; }
}
public interface IEntityContent { }
public interface IThingService<T>
{
void DoThing(T item);
}
public class BaseEntity<T> : IEntity
where T : IEntityContent
{
public abstract T Data { get; set; }
}
public class FooEntity : BaseEntity<FooContent>
{
public override FooContent Data { get; set; }
}
public class FooContent : IEntityContent
{
// Some properties
}
public class ThingService<T> : IThingService<T>
where T : IEntity
{
public void DoThing(T item)
{
Serializer.Instance.Serialize(item.Content);
}
}
The signature of Serializer.Instance.Serialize is:
string Serialize<T>(T from)
But I get the following:
'BaseEntity<T>' does not implement interface member 'IEntity.Data'. 'BaseEntity<T>.Data' cannot implement 'IEntity.Data' because it does not have the matching return type of 'IEntityContent'
Why is this? As it stands, I am forced to create a bunch of near-identical strongly-typed implementations of IThingService - which is a shedload of duplication - just to specify different type arguments which, as far as I can see, should be generic.
Is this somehow related to a lack of covariance in BaseEntity? How can I make ThingService<T> work?
Why not simply have:
public interface IEntity<T>
{
T Data { get; set; }
}
For an implementation of the interface has to match the interface (as you've not declared any contra/covariance), including the return types (hence your error message)
Create method with access to similar named field, but different types of object without inheritance in c#.
For ex. I have 2 Classes:
public class MyClass1
{
public int Id { get; set; }
}
public class MyClass2
{
public int Id { get; set; }
}
And I need to create method and pass to it instance of each Classes:
DoStuff(new MyClass1());
DoStuff(new MyClass2());
And Method will be like this:
private void DoStuff<T>(T obj)
{
int i = obj.Id(); // here is the problem
}
Yes, problem is, that obj can't resolve Id. Solution simple - create RootClass with Id property, and use public class MyClass1: RootClass... , but I can't do this.
Question is: Can I use line like int i = obj.Id(); without creating RootClass?
Edit: I need answers like: No, because.... or Yes, do this.....
This is typically why interfaces exist: describe a common contract, but with no relationship between the classes.
I would suggest you to create this interface
public interface IHasId {
int Id { get; set; }
}
public class MyClass1 : IHasId
{
public int Id { get; set; }
}
public class MyClass2 : IhasId
{
public int Id { get; set; }
}
...
private void DoStuff<T>(T obj)
where T : IHasId // constraint my be moved to the class declaration
{
int i = obj.Id();
}
Creating this interface will let you avoid introducing a root class, which may be not desired if the classes has no root behavior.