繁体   English   中英

如何创建C#泛型方法

[英]How to create a C# generic method

我有一种方法可以将粘贴复制到许多类中。 该方法将模型合并到IdNameViewModel中。 如何使用此方法创建一个类,我可以在存储库模型中传递该类并获取该模型的IdName列表?

注意:ProjectValue是例如我要传递的模型/类,但实际上它可以是包含id和name属性的任何模型/类。

private IdNameVM HydrateEntityToVM(ProjectValue projectValue)
{
    if (projectValue == null) return null;

    return new IdNameVM()
    {
        Id = projectValue.Id,
        Name = projectValue.Name
    };
}

这是我根据以下答案得出的结果:

public class GenericHydrateIdName<TModel> where TModel : INameId
    {
        public IdNameVM HydrateEntityToVM(TModel model)
        {
            if (model == null) return null;

            return new IdNameVM()
            {
                Id = model.Id,
                Name = model.Name
            };
        }
    }
}

请注意,如果有人在追随,上面的类会导致过多的工作,并且违反了“清洁代码原则”。 我在下面使用了扩展方法。

基本上,我看到的最好的类型安全的方法是拥有一个接口。

interface INameId
{
    int Id { get; set; }
    string Name { get; set; }
}

您可以在要使用它的每个类中使用此接口。根据您当前的用法,我建议使用扩展功能

static class VMExtensions
{

    public static IdNameVM HydrateEntityToVM<TModel>(this TModel model)
        where TModel : INameId
    {
        if (model == null) return null;

        return new IdNameVM()
        {
            Id = model.Id,
            Name = model.Name
        };
    }

    // update: without generics as Marcus Höglund pointed out
    public static IdNameVM HydrateEntityToVM2(this INameId model)
    {
        if (model == null) return null;

        return new IdNameVM()
        {
            Id = model.Id,
            Name = model.Name
        };
    }

    static void Test()
    {
        var model = new ProjectValue();
        var model2 = new AnotherModel();

        var viewModel = model2.HydrateEntityToVM();
        var viewModel2 = model2.HydrateEntityToVM();

    }

}

如果您不想将接口添加到所有模型中,则可以使用反射(但请注意,这确实很慢)。

更新资料

正如Marcus所指出的,在这种情况下,在函数中使用泛型没有任何实际意义。 您可以使用直接使用该接口的HydrateEntityToVM2实现。 但是,在将来,如果要使用IdNameVM<TModel>类的东西,以便在需要时仍可以访问原始模型,则具有泛型的HydrateEntityToVM函数将很有帮助。

这些是C#的基础。 看一下这个链接

class MyClass<T> where T : ProjectValue
{
    private IdNameVM HydrateEntityToVM(T projectValue)
    {
        if (projectValue == null) return null;

        return new IdNameVM()
        {
            Id = projectValue.Id,
            Name = projectValue.Name
        };
    }
}

如果您不知道模型的抽象(但请注意,此方法可以使用任何包含id和name公共属性的对象),请尝试以下操作:

public void SomeGenericMethod<T>(T model) where T : class
{
    if (model == null) return null;

    var propId = model.GetType().GetProperty("id");
    var propName = model.GetType().GetProperty("name");
    if (propId == null || propName == null)
        return;


    return new IdNameVM()
    {
        Id = model.Id,
        Name = model.Name
    };
}

创建通用方法时,必须牢记一些规则

  1. 您将要支持什么类型
  2. 会有什么结果
  3. 解决方案之间必须有奇异之处

让我们以上述示例为例:您需要一个名称为HydrateEntityToVM的通用方法。 第一步是方法的声明语法以及从T类型的Strong Type进行对象强制转换。

这里要注意的一点是,您正在传递T类型,并且希望结果始终为IdNameVM类,那么您的实现应为:

//The Method declaration of T type
private IdNameVM  HydrateEntityToVM<T>(T projectValue)
{
     //Checking whether the object exists or not
     //if null than return the default value of IdNameVM
     if(projectValue == null) return default(IdNameVM);  

     //Checking if we are supporting the implementation or not for that class
     //In your case YourStrongTypeClass is ProjectValue Class
     if(projectValue is YourStrongTypeClass) 
     {

         //Casting the T object to strong type object
         var obj = projectValue as YourStrongTypeClass;

         return new IdNameVM()
         {
            Id = obj.Id,
            Name = obj.Name
         };
     } 
     else
     {
        //The else statement is for if you want to handle some other type of T implementation
        throw new NotImplementedException($"The type {typeof(T)} is not implemented");
     }
}

我喜欢内维尔·纳泽拉内(Neville Nazerane)的回答,因为它消除了反思的需要。 但是,如果您确实想使用反射来做到这一点,那么即使找不到匹配的Id或Name属性,下面也是一种构造结果的可行方法。

请注意,在此示例中,我没有添加任何检查I和Name属性的类型在T和TResult之间是否匹配。

   public static TResult HydrateEntityToVM<T, TResult>(T inputValue, TResult resultValue) where T : class 
    {
        if (inputValue == null || resultValue == null)
            return default(TResult);

        var idValue = inputValue.GetType().GetProperty("Id").GetValue(inputValue);
        var nameValue = inputValue.GetType().GetProperty("Name").GetValue(inputValue);

        object instance;
        if (resultValue == null)
        {
            var ctor = resultValue.GetType().GetConstructor(Type.EmptyTypes);
            instance = ctor.Invoke(new object[] {});
        }
        else
        {
            instance = resultValue;
        }

        var idProp = instance.GetType().GetProperty("Id");
        if (idProp != null)
        {
            if (idProp.CanWrite)
                idProp.SetValue(instance, idValue);
        }

        var nameProp = instance.GetType().GetProperty("Name");
        if (nameProp != null)
        {
            if (nameProp.CanWrite)
                nameProp.SetValue(instance, nameValue);
        }

        return (TResult) instance;
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM