C# Generic and override methods

♀尐吖头ヾ 提交于 2019-12-11 16:26:51

问题


I created a question and realized that it was due to some design error on my part. However, I do think that that concept can be useful and I would like to know how to solve an issue similar, if possible.

I want to create an algorithm that adds up 2 numbers, be it string or int. I also want to be able to output everything in the console and would like to avoid code duplication. I create a generic interface that changes according to the model. Then a class that handles the addition of the two members. Note that the data comes from the handler classes (which in real life scenario, get information to fill model from external data).

Please note that I do know that I know there are much simpler ways of doping this, but I want to understand why it does not work. Now, the code does not compile in the ValidateHandler<T>(IAddHandler<T> handler) due to cannot convert from 'T' to 'Test.Models.StringModel'. Why cannot it select the right overridden method ? I tried adding generics to the overridden method, but it still does not work. How can I make ValidateHandler<T> select the right method from it's type ?

Here is the code I wrote.

Models:

public class IntegerModel
{
    public int A { get; set; }

    public int B { get; set; }

    public int C { get; set; }
}

public class StringModel
{
    public string A { get; set; }

    public string B { get; set; }

    public string C { get; set; }
}

Interface:

public interface IAddHandler<T>
{
    T Add();

    void GetData();
}

Handlers:

public class IntegerHandler : IAddHandler<IntegerModel>
{
    public IntegerModel IntegerModel { get; set; }

    public void GetData()
    {
        // Get Info to Add from external file for example
        IntegerModel = new IntegerModel { A = 10, B = 20 };
    }

    public IntegerModel Add()
    {
        IntegerModel.C = IntegerModel.A + IntegerModel.B;

        return IntegerModel;
    }
 }

public class StringHandler : IAddHandler<StringModel>
{
    public StringModel StringModel { get; set; }

    public void GetData()
    {
        // Get Info to Add from external file for example
        StringModel = new StringModel { A = "10", B = "20" };
    }

    public StringModel Add()
    {
        StringModel.C = StringModel.A + StringModel.B;
        return StringModel;
    }
 }

Here is the Main with it's function

public static void Main(string[] args)
{
    var integerHandler = new IntegerHandler();
    var stringHandler = new StringHandler();

    ValidateHandler(integerHandler);
    ValidateHandler(stringHandler);
}

public static void ValidateHandler<T>(IAddHandler<T> handler)
{
    handler.GetData();
    var result = handler.Add();

    WriteResults(result);
}

public static void WriteResults(StringModel model)
{
    Console.WriteLine(model.C);
}

public static void WriteResults(IntegerModel model)
{
    Console.WriteLine(model.C);
}

I know I can do the following, but it seems ineffective in doing so and I do not see the point of using generics then.

public static void ValidateHandler<T>(IAddHandler<T> handler)
{
    handler.GetData();
    var result = handler.Add();

    if (typeof(T) == typeof(StringModel))
    {
        WriteResults(result as StringModel);
    }
    else if (typeof(T) == typeof(IntegerModel))
    {
        WriteResults(result as IntegerModel);
    }
}

回答1:


Here's what I would recommend. This approach commits less heavily to generics. I believe it will be easier to get your head around than a fully generic solution.

public interface IResult
{
    Object Result { get; }
}

public interface IModel : IResult
{
    Object A { get; }
    Object B { get; }
}

public class Model<T> : IModel
{
    public T A { get; set; }
    public T B { get; set; }
    public T Result { get; set; }

    //  The "IModel.*" prefix means this is an "explicit" implementation of the IModel 
    //  interface. That means that ordinarily, model.A gets you the above strongly typed
    //  A property, but with an explicit cast to IModel, you get the non-generic IModel 
    //  version: model.A is int or whatever T is; ((IModel)model).A is object. 
    //
    //  These getters don't recurse because this is of type Model<T>, not IModel.
    //  If T is List<String>, a subclass could override this to return 
    //  String.Join(", ", Result);
    Object IModel.A => A;
    Object IModel.B => B;
    Object IResult.Result => Result;
}

public interface IAddHandler<T> where T : IModel
{
    T Model { get; set; }
    T Add();

    void GetData();
}

public class IntegerHandler : IAddHandler<Model<int>>
{
    public Model<int> Model { get; set; }

    public void GetData()
    {
        // Get Info to Add from external file for example
        Model = new Model<int> { A = 10, B = 20 };
    }

    public Model<int> Add()
    {
        Model.Result = Model.A + Model.B;

        return Model;
    }
}

public class StringHandler : IAddHandler<Model<string>>
{
    public Model<string> Model { get; set; }

    public void GetData()
    {
        // Get Info to Add from external file for example
        Model = new Model<string> { A = "10", B = "20" };
    }

    public Model<string> Add()
    {
        Model.Result = Model.A + Model.B;

        return Model;
    }
}

Main:

class Program
{
    public static void Main(string[] args)
    {
        var integerHandler = new IntegerHandler();
        var stringHandler = new StringHandler();

        ValidateHandler(integerHandler);
        ValidateHandler(stringHandler);
    }

    //  This method must require T to be IModel because IAddHandler<T> requires 
    //  T to be IModel.
    public static void ValidateHandler<T>(IAddHandler<T> handler) where T : IModel
    {
        handler.GetData();
        var result = handler.Add();

        //  IModel inherits from IResult. Hence, anything that implements IModel 
        //  must implement IResult. So this is an implicit cast, even though IResult 
        //  is implemented explicitly. 
        WriteResults(result);
    }

    //  The parameter here could be IModel instead, but maybe there are other non-model 
    //  classes that implement IResult.
    public static void WriteResults(IResult result)
    {
        Console.WriteLine(result.Result);
    }
}


来源:https://stackoverflow.com/questions/58597045/c-sharp-generic-and-override-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!