Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

120
Visualizações
Is there a way to type check a generic function parameter using the shape of the object instead of inheritance?

I have a few EF model classes that I want to create. Each class has a few common properties that I want to set before inserting a new entity, for example:

public partial class BlogPost {
  public DateTime CreatedTime { get; set; }
  public string CreatorName { get; set; }
  public string PostTitle { get; set; }
  public string PostText { get; set; }
}

public partial class Comment {
  public DateTime CreatedTime { get; set; }
  public string CreatorName { get; set; }
  public string CommentText { get; set; }
}

...

When I create these classes, I'm instantiating them like so:

var blogPost = new BlogPost {
  CreatedTime = DateTime.UtcNow,
  CreatorName = creatorName,
  PostTitle = postTitle,
  PostText = postText,
};

var comment = new Comment {
  CreatedTime = DateTime.UtcNow,
  CreatorName = creatorName,
  ...
};

...

I want to create a method to automatically set some of the common properties so I don't need to manually type them out for each class with the same properties. Since they don't extend the same class or implement the same interface, I'm wondering how this can be achieved. My first thought was to use a generic method; however, I don't know if there's a way to specify what properties the generic type should have without them extending the same class (similar to TypeScript's "duck typing"). My desired method looks something like this:

public void SetInitialProperties<T>(T dbEntity, DateTime createdTime, string creatorName) where T : ??? {
  dbEntity.CreatedTime = createdTime;
  dbEntity.CreatorName = creatorName;
}

...

var blogPost = new BlogPost { PostTitle = postTitle, PostText = postText };
SetInitialProperties(blogPost, createdTime, creatorName);

Worst case scenario if I can't use a generic, I could always use dynamic; however, I'd like to keep type checking if possible.

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

You can achieve what you want using reflection. You can pass in an object and resolve it's type, then get all the public properties of that given type and find if you have one called CreatedTime for example. Then you can set the value of the given property on the passed dbEntity object. However, I do not recommend this solution:

public void SetInitialProperties(object dbEntity, DateTime createdTime, string creatorName) {
        // get the passed object's properties and find the one called CreatedTime
        var createdTimePropertyInfo = dbEntity.GetType().GetProperties().Where(i => i.Name == "CreatedTime").FirstOrDefault();
        // below line is equal to: dbEntity.CreatedTime = createdTime;
        createdTimePropertyInfo.SetValue(dbEntity, createdTime);
        
        var creatorNamePropertyInfo = dbEntity.GetType().GetProperties().Where(i => i.Name == "CreatorName").FirstOrDefault();
        creatorNamePropertyInfo.SetValue(dbEntity, creatorName);
    }

You would be better off on the long run by creating a common interface or even an abstract base class so you don't have to implement CreatedTime and CreatorName and other properties for every EF model. It would look like the following:

public interface IUserEntry
{
    DateTime CreatedTime { get; set; }
    string CreatorName { get; set; }
}

public abstract class UserEntryBase : IUserEntry
{
    public DateTime CreatedTime { get; set; }
    public string CreatorName { get; set; }
}

public partial class BlogPost : UserEntryBase
{
    public string PostTitle { get; set; }
    public string PostText { get; set; }
}

public partial class Comment : UserEntryBase
{
    public string CommentText { get; set; }
}

And your SetInitialProperties would be pretty simple:

public void SetInitialProperties(IUserEntry dbEntity, DateTime createdTime, string creatorName)
    {
        dbEntity.CreatedTime = createdTime;
        dbEntity.CreatorName = creatorName;
    }

Once you develop onto an interface, you achieve much more flexibility than by using reflection or a dynamic type, since you get the compile-time checking that was mentioned before me and you can see the common properties of your models.

over 4 years ago · Santiago Trujillo Relatório

0

You can't do that in C# because C# uses a nominal type system and not a structural type system.
For your particular case you have to come up with an interface that contains the properties in common and which will be implemented by both entities, then use that new interface as you generic function parameter constraint.

over 4 years ago · Santiago Trujillo Relatório

0

If you're absolutely sure the properties will have the same name, you could pass a dynamic to set property values. However, this prevents any compile-time checking of the typing, so if you accidently pass an incompatible type it won't be caught until runtime.

public void SetInitialProperties(dynamic dbEntity, DateTime createdTime, string creatorName) {
  dbEntity.CreatedTime = createdTime;
  dbEntity.CreatorName = creatorName;
}
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda