Hoe kan ik waarden in de db toewijzen aan mijn objecten als het type bekend is tijdens runtime?

Mijn database heeft een tabel die er als volgt uitziet:

conditionID, conditionType, conditionValue

ConditionType is an enumeration with values like Integer, String, DateTime, etc.

De ConditionValue wordt opgeslagen als een tekenreeks.

Nu wil ik deze rij inkapselen in een klasse zodat ik vergelijkingen kan uitvoeren op de ConditionValue, dus dit zoals EqualTo, GreaterThan, LessThan etc.

Op dit moment is mijn ontwerp niet correct omdat ik methoden heb zoals ( otherValue is de waarde die ik vergelijk met):

GreaterThan(string value, string otherValue);
GreaterThan(int value, int otherValue);
GreaterThan(DateTime value, DateTime otherValue);

Kan ik op de een of andere manier een klasse ConditionValue maken die deze informatie bevat, zodat ik het volgende kan doen:

GreaterThan(IConditionValue condition, IConditionValue otherValue)
1
toegevoegd de auteur Ash Burlaczenko, de bron
Je moet eens kijken naar de links in mijn eerste bericht. Het inkapselen van datatype-specifieke functionaliteit is AOM of vereenvoudigde variaties, zoals het Type Object-patroon.
toegevoegd de auteur Jeffrey, de bron

5 antwoord

Dit moet eenvoudig kunnen worden gemodelleerd met behulp van het Adaptive Object Model of Type Object-patronen. Het is misschien wel meer dan dood voor je situatie.

http://adaptiveobjectmodel.com/

http://www.cs.ox.ac.uk/jeremy .gibbons/dpa/typeobject.pdf

Hiermee kunt u uw model tijdens runtime opnieuw configureren, naar wens gedrag toevoegen/verwijderen, regels definiëren, enz.

2
toegevoegd
interessant leest dankjewel.
toegevoegd de auteur codecompleting, de bron

Alle typen die u hebt genoemd, implementeren ICcomparable , zodat u eenvoudig kunt aannemen dat type zal ICvergelijkbaar zijn en de methode CompareTo() gebruiken.

bool GreaterThan(IComparable value, IComparable otherValue)
{
    return value.CompareTo(otherValue) > 0;
}
1
toegevoegd

Dit is een zeer naïef voorbeeld.

public class ConditionValue
{
    private object value;
    private IValueType valueType;

    public ConditionValue(object value, IValueType valueType)
    {
        this.value = value;
        this.valueType = valueType;
    }

    public bool GreaterThan(ConditionValue cv)
    {
        return valueType.GreaterThan(this.value, cv.value);
    }
}

public interface IValueType
{
    bool GreaterThan(object left, object right);
}

public class IntegerType : IValueType
{
    public bool GreaterThan(object left, object right)
    {
        return (int)left > (int)right;
    }
}
1
toegevoegd
ok dit maakt dit voor mij duidelijker, ik kan ook controleren of het een verzameling is in de integer.GreaterThan methode etc.
toegevoegd de auteur codecompleting, de bron
en die fabriek zal een int, een string of een List retourneren? hmmm .. niet zeker of ik het nog krijg, sorry.
toegevoegd de auteur codecompleting, de bron
U kunt de interface van IValueType gebruiken om uw gegevenstype "archetypen" te definiëren die in de database worden opgeslagen. Heb een fabrieksmethode die het conditionType-opsommingsteken inneemt en een exemplaar van ConditionValue retourneert met de waarde en de IValueType-handler voor die enumwaarde.
toegevoegd de auteur Jeffrey, de bron
    public enum ValueType
    {
        String = 0,
        Integer = 1,
        CustomDataType = 3
    }

    public interface IValueType : IComparer
    {
        string ToString(object obj);
    }

    public class IntegerValueType : IValueType
    {
        public int Compare(object left, object right)
        {
            return ((int)left).CompareTo((int)right);
        }

        public string ToString(object obj)
        {
            return ((int)obj).ToString();
        }
    }

    public class StringValueType : IValueType
    {
        public int Compare(object left, object right)
        {
            return ((string)left).CompareTo((string)right);
        }

        public string ToString(object obj)
        {
            return ((string)obj).ToString();
        }
    }

    public class Value : IComparable { private object value; private IValueType valueType; public Value(object value, IValueType valueType) { this.value = value; this.valueType = valueType; } public static implicit operator Value(string value) { return ValueFactory.Create(value, ValueType.String); } public int CompareTo(Value obj) { return this.valueType.Compare(this.value, obj.value); } public static bool operator <(Value left, Value right) { return left.CompareTo(right) == -1; } public static bool operator >(Value left, Value right) { return left.CompareTo(right) == 1; } public static bool operator ==(Value left, Value right) { return left.CompareTo(right) == 0; } public static bool operator !=(Value left, Value right) { return left.CompareTo(right) != 0; } public override string ToString() { return this.valueType.ToString(this.value); } } public class ValueFactory { private static IDictionary _valueTypes = new Dictionary(); static ValueFactory() { _valueTypes.Add(ValueType.String, new StringValueType()); _valueTypes.Add(ValueType.Integer, new IntegerValueType()); } public static Value Create(object value, object valueType) { // //This logic could be extended to find a ValueType that supports //one of the types in the objects inheritance tree. This would //also require creating an ObjectValueType, which would be a last //resort in the case of the object type not being supported. // if (!_valueTypes.ContainsKey(valueType)) throw new ArgumentException("valueType is not supported"); return new Value(value, _valueTypes[valueType]); } } class Program { static void Main(string[] args) { int x = 32; int y = 16; Value cx = ValueFactory.Create(x, ValueType.Integer); Value cy = ValueFactory.Create(y, ValueType.Integer); Console.WriteLine("cx = "+cx); Console.WriteLine("cy = "+cy); Console.WriteLine("x< cy); Console.WriteLine("x>y = {0}", cx > cy); Console.WriteLine("x==y = {0}", cx == cy); Console.WriteLine("x!=y = {0}", cx != cy); Value name = ValueFactory.Create("Jeffrey Schultz", ValueType.String); Console.WriteLine("{0} == You = {1}", name, name == "You"); Console.ReadLine(); } } 
1
toegevoegd
public interface IValueComparer
{
    bool GreaterThan(string source, string destination);
    bool LessThan(string source, string destination);
}

public class IntToIntComparer : IValueComparer
{
    public bool GreaterThan(string source, string detination)
    {
       //better use TryParse and handle exception
        return Int32.Parse(source) > Int32.Parse(detination);
    }

    public bool LessThan(string source, string detination)
    {
       //better use TryParse and handle exception
        return Int32.Parse(source) < Int32.Parse(detination);
    }
}

public class DateToDateComparer : IValueComparer
{
    public bool GreaterThan(string source, string detination)
    {
       //better use TryParse and handle exception
        return DateTime.Parse(source) > DateTime.Parse(detination);
    }

    public bool LessThan(string source, string detination)
    {
       //better use TryParse and handle exception
        return DateTime.Parse(source) < DateTime.Parse(detination);
    }
}

public class StringToStringComparer : IValueComparer
{
    public bool GreaterThan(string source, string detination)
    {
        return source.Length > detination.Length;
    }

    public bool LessThan(string source, string detination)
    {
        return source.Length < detination.Length;
    }
}


public class Condition
{
    public int ID { get; set; }
    public string Value { get; set; }
    public string Type { get; set; }
    public IValueComparer Comparer{get; set;}

    public static string Integer { get { return "Integer"; } }
    public static string String { get { return "String"; } }
    public static string DateTime { get { return "DateTime"; } }

    public static Condition CreateForType(string type)
    {
        if (type == Integer)
            return new Condition { Type = type, Comparer = new IntToIntComparer() };
        if (type == String)
            return new Condition { Type = type, Comparer = new StringToStringComparer() };
        if (type == DateTime)
            return new Condition { Type = type, Comparer = new DateToDateComparer() };
        return null;
    }

    public bool GreaterThan(Condition destination)
    {
        return Comparer.GreaterThan(Value, destination.Value);
    }

    public static bool operator >(Condition source, Condition destination)
    {
        return source.GreaterThan(destination);
    }

    public static bool operator <(Condition source, Condition destination)
    {
        return source.LessThan(destination);
    }

    public bool LessThan(Condition destination)
    {
        return Comparer.LessThan(Value, destination.Value);
    }
}

        var condition1 = Condition.CreateForType("Integer");
        condition1.ID = 1;
        condition1.Value = "5";

        var condition2 = Condition.CreateForType("Integer");
        condition2.ID = 2;
        condition2.Value = "10";

        bool result1 = condition1 > condition2;
        bool result2 = condition1.LessThan(condition2);
0
toegevoegd
Maar ik krijg de gegevens uit de database tijdens runtime, niet zeker hoe dit zal werken?
toegevoegd de auteur codecompleting, de bron
@MohamedAbed Ik gaf een voorbeeld van mijn databasekolommen in de vraag, dus ik zal rijen met waarden voor die kolommen retourneren.
toegevoegd de auteur codecompleting, de bron
U moet een klasse maken die het gegevenstype vertegenwoordigt dat is gedefinieerd door het conditionType, zoals IntegerType. IntegerType weet hele getallen te vergelijken. U hebt ook een voorwaarde nodig die een waarde en een gegevenstype handler accepteert.
toegevoegd de auteur Jeffrey, de bron
Hoe kun je dit vergelijken met getallen? Hoe zou u "uw code hier" schrijven? Ik ben er vrij zeker van dat als je "if (source> destination)" schrijft, deze niet compileert.
toegevoegd de auteur Jeffrey, de bron
hoe krijg je de gegevens uit de database, geef een voorbeeld
toegevoegd de auteur Mohamed Abed, de bron
Bijgewerkt antwoord met een voorbeeldoplossing
toegevoegd de auteur Mohamed Abed, de bron