Pergunta

Actualmente tenho esse tipo de código:

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2)
{
    if (MainObject is SomeClassType1)
    {
        SomeClassType1 HelpObject = (SomeClassType1)MainObject;
        HelpObject.Property1 = Arg1;
        HelpObject.Property2 = Arg2;
    }
    else if (MainObject is SomeClassType2)
    {
        SomeClassType2 HelpObject = (SomeClassType2)MainObject;
        HelpObject.Property1 = Arg1;
        HelpObject.Property2 = Arg2;
    }
}

Assumindo que SomeClassType1 e SomeClassType2 têm o mesmo conjunto de propriedades que deseja atribuir (embora possam diferir em outros), não é possível lançar dinamicamente MainObject para o tipo apropriado e, em seguida, atribuir o valor, sem duplicar o código ? Isto é o que eu gostaria de ver no final:

private void FillObject(Object MainObject, Foo Arg1, Bar Arg2)
{
    Type DynamicType = null;

    if (MainObject is SomeClassType1)
    {
        DynamicType = typeof(SomeClassType1);
    }
    else if (MainObject is SomeClassType2)
    {
        DynamicType = typeof(SomeClassType2);
    }

    DynamicType HelpObject = (DynamicType)MainObject;
    HelpObject.Property1 = Arg1;
    HelpObject.Property2 = Arg2;
}

E, obviamente, C # reclama de não ser capaz de encontrar DynamicType:

O tipo ou nome do namespace 'DynamicType' não pôde ser encontrado (faltam usando uma diretiva ou uma referência assembly?)

É algo como isto possível em C # 2.0? Se é mais confuso do que meu código atual, que eu vejo nenhum ponto em fazer isso, mas eu estou muito interessado em saber. Obrigado!

EDIT: Só para esclarecer, eu entendo perfeitamente que a implementação de uma interface é a mais adequada e provavelmente solução correta. Dito isto, estou mais interessado em ver como eu poderia fazer isso sem implementar uma interface. Obrigado por grandes respostas!

Foi útil?

Solução

Parece que ambos os tipos que se preocupam implementar as mesmas duas propriedades. Nesse caso, o que você quer fazer é definir uma interface para essas propriedades:

public interface IMyInterface
{
   public Foo Property1 {get; set;}
   public Bar Property2 {get;set;}
}

Em seguida, certifique-se cada uma de suas aulas de dizer ao compilador que implementar essa nova interface. Finalmente, use um método genérico com um tipo de argumento que é restrito para que interace:

private void FillObject<T>(T MainObject, Foo Arg1, Bar Arg2) 
    where T : IMyInterface
{
    MainObject.Property1 = Arg1;
    MainObject.Property2 = Arg2;
}

Note que, mesmo com o código extra para declarar a interface, estes fragmentos ainda acabar mais curto do que qualquer um dos trechos em que você postou a pergunta, e este código é muito mais fácil para estender se o número de tipos você se preocupa com os aumentos .

Outras dicas

Essencialmente o que você está fazendo aqui está escrevendo uma instrução switch com base no tipo fo o objeto. Não há inerentemente boa maneira de fazer isso que não seja o seu primeiro exemplo (que é tedioso na melhor das hipóteses).

Eu escrevi uma pequena estrutura para ligar tipos que faz com que a sintaxe um pouco mais conciso. Ele permite que você escrever código como o seguinte.

TypeSwitch.Do(
    sender,
    TypeSwitch.Case<Button>(
        () => textBox1.Text = "Hit a Button"),
    TypeSwitch.Case<CheckBox>(
        x => textBox1.Text = "Checkbox is " + x.Checked),
    TypeSwitch.Default(
        () => textBox1.Text = "Not sure what is hovered over"));

Blog Post: http: // blogs .msdn.com / JaredPar / Arquivo / 2008/05/16 / comutação-on-types.aspx

Você será capaz de fazer alterações SomeClassType1, SomeClassType2 etc? Se sim, então eu sugiro que você criar uma interface que contém as suas propriedades comuns e, em seguida, typecast a esta interface dentro FillObject() para definir as propriedades.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SO566510
{
    interface IMyProperties
    {
        int Property1 { get; set; }
        int Property2 { get; set; }
    }

    class SomeClassType1 : IMyProperties
    {
        public int Property1 { get; set; }
        public int Property2 { get; set; }
    }

    class SomeClassType2 : IMyProperties
    {
        public int Property1 { get; set; }
        public int Property2 { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var obj1 = new SomeClassType1();
            var obj2 = new SomeClassType2();

            FillObject(obj1, 10, 20);
            FillObject(obj2, 30, 40);

        }

        private static void FillObject(IMyProperties objWithMyProperties
                                   , int arg1, int arg2)
        {
            objWithMyProperties.Property1 = arg1;
            objWithMyProperties.Property2 = arg2;
        }
    }
}
private void FillObject(Object MainObject, Foo Arg1, Bar Arg2)
{
    Type t = MainObject.GetType();

    t.GetProperty("Property1").SetValue(MainObject, Arg1, null);
    t.GetProperty("Property2").SetValue(MainObject, Arg2, null);
}

Algumas ideias:

  1. Ter os dois tipos herdar do mesmo tipo que tem as propriedades comuns
  2. Ter os dois tipos implementar a mesma interface que tem as propriedades comuns
  3. Use reflexão para definir as propriedades em vez de colocá-los diretamente (este é provavelmente mais feio do que vale a pena)
  4. Use o novo dinâmico recurso , eu não tentei isso, mas parece que pode resolver o seu problema

Em vez de tentar elenco, talvez você pode tentar definir as propriedades usando a reflexão.

Estou lançando dinamicamente objetos usando Reflexão em um aplicativo ASP.NET MVC. Basicamente, eu enumerar as propriedades de uma classe, encontrar o valor correspondente no armazenamento de dados e dinamicamente converter o valor e atribuí-lo à ocorrência de objeto. Ver meu blog dinâmico Fundição com .NET

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top