如何创建C#通用方法

时间:2018-11-10 17:08:28

标签: c# generics

我有一种方法可以将粘贴复制到许多类中。该方法将模型合并到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
            };
        }
    }
}

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

4 个答案:

答案 0 :(得分:2)

基本上,我可以看到的最好的类型安全方式是使用接口。

private pickupRequest = new BehaviorSubject<boolean>(false);
public pickupStatus = this.pickupRequest.asObservable();

changePickupStatus(value: boolean) {
this.pickupStatus.emit(value);
}

constructor(public http: HttpClient) {
//console.log('Hello PickuprequestProvider Provider');

}

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

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

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

更新

正如Marcus所指出的,在这种情况下,在函数中使用泛型没有实际意义。您可以使用直接使用该接口的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(); } } 实现。但是,在将来,如果您想使用类似HydrateEntityToVM2之类的东西,以便仍然可以在需要时访问原始模型,则使用泛型的IdNameVM<TModel>函数将很有帮助。

答案 1 :(得分:0)

这些是C#的基础。看看这个link

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
    };
}

答案 2 :(得分:0)

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

  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");
     }
}

答案 3 :(得分:0)

我喜欢内维尔·纳泽兰(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;
    }